-9-
In this chapter, we have picked
up one of the Microsoft samples called the Class Browser and presented it to
you in a straightforward and uncomplicated format, stripped of all its
convolutions.
This sample displays the
following:
• all the namespaces
• the classes within each namespace
• the functions within each class
• the parameters of each function, and
so on.
It is a considerably large
program, and hence appears intimidating. As is customary, we shall first
partition this program into smaller programs and after deciphering every small
part, we shall coalesce them together to form one composite program.
At the end of this explanation,
you would not only be in a position to write complex ASP.Net code, but you
would also have unraveled the mysteries of the Reflection API, which is a technique
used to determine the contents of a class.
We have retained the function
names and variable names as given in the original code, with the anticipation
that sooner or later, you would be motivated enough to read the source code
written by the programmers at Microsoft. Our example will work as effectively,
sans the comely appearance of the original code.
Our first program displays a
series of namespaces in a single column. These names are displayed as
hyperlinks. Before we dive headlong into the program, we first need to create
the file named web.config in the sub-directory c:\inetpub\wwwroot.
web.config
<configuration>
<configSections>
<sectionGroup
name="system.web">
<section
name="ClassBrowser"
type="System.Configuration.NameValueSectionHandler,System"/>
</sectionGroup>
</configSections>
<system.web>
<compilation
debug="true"/>
<ClassBrowser>
<add
key="Data Library" value="System.Data" />
<add
key="ASP.NET Class Library" value="System.Web" />
<add
key=".NET Framework class Library" value="mscorlib" />
</ClassBrowser>
</system.web>
</configuration>
a.aspx
<%@ Import NameSpace="System.Collections" %>
<%@ Import NameSpace="System.Collections.Specialized"
%>
<%@ Import NameSpace="System.Reflection" %>
<html>
<head>
<script runat="server" language="C#">
ArrayList ModuleName = new ArrayList();
void Page_Load(Object Sender, EventArgs e)
{
NameValueCollection ConfigSettings;
ConfigSettings =
(NameValueCollection)Context.GetConfig("system.web/ClassBrowser");
Response.Write(ConfigSettings.Count.ToString() +
"<br>");
for (int i = 0; i < ConfigSettings.Count; i++)
{
Response.Write(ConfigSettings[i].ToString() +
"<br>");
ModuleName.Add(ConfigSettings[i].ToString());
}
DisplayNamespaces();
}
void DisplayNamespaces()
{
ArrayList NameSpaceList
= new ArrayList();
Hashtable NameSpaceHash = new Hashtable();
Response.Write(ModuleName.Count.ToString() +
"<br>");
for (int y = 0; y < ModuleName.Count; y++)
{
Assembly a = Assembly.Load(ModuleName[y].ToString());
Module[] CorRuntime =
a.GetModules();
Type[] CorClasses =
CorRuntime[0].GetTypes();
Response.Write(ModuleName[y].ToString() + " Modules:" +
CorRuntime.Length.ToString() + " Type:" +
CorClasses.Length.ToString() + "<br>" );
for( int x=0; x < CorClasses.Length; x++ )
{
if ( CorClasses[x].Namespace != null )
{
if (!NameSpaceHash.ContainsKey(CorClasses[x].Namespace)
&& CorClasses[x].IsPublic)
{
NameSpaceHash.Add(CorClasses[x].Namespace,"");
NameSpaceList.Add(CorClasses[x].Namespace);
}
}
}
}
NameSpaceList.Sort();
Namespace1.DataSource = NameSpaceList;
Namespace1.DataBind();
}
</script>
</head>
<body>
<form runat="server">
<asp:DataList runat=server id="Namespace1"
RepeatLayOut="flow">
<headertemplate>
Namespaces <br>
</headertemplate>
<itemtemplate>
<asp:HyperLink runat="server" text=<%#
Container.DataItem %> NavigateUrl=<%# "a.aspx?namespace=" +
Container.DataItem %> />
</itemtemplate>
<selecteditemtemplate>
<b><asp:HyperLink runat=server text=<%#
Container.DataItem %>/></b>
</selecteditemtemplate>
</asp:DataList>
</form>
</body>
</html>
Output
3
System.Data
System.Web
mscorlib
3
System.Data Modules:1 Type:427
System.Web Modules:1 Type:663
mscorlib Modules:1 Type:1410
Namespaces
Microsoft.Win32
System
System.Collections
System.Configuration.Assemblies
System.Data
System.Data.Common
System.Data.OleDb
System.Data.SqlClient
System.Data.SqlTypes
System.Diagnostics
System.Diagnostics.SymbolStore
System.Globalization
System.IO
System.IO.IsolatedStorage
System.Reflection
System.Reflection.Emit
System.Resources
System.Runtime.CompilerServices
System.Runtime.CompilerServices.CSharp
System.Runtime.InteropServices
System.Runtime.InteropServices.Expando
System.Runtime.Remoting
System.Runtime.Remoting.Activation
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Contexts
System.Runtime.Remoting.Lifetime
System.Runtime.Remoting.Messaging
System.Runtime.Remoting.Metadata
System.Runtime.Remoting.Metadata.W3cXsd2001
System.Runtime.Remoting.Proxies
System.Runtime.Remoting.Services
System.Runtime.Serialization
System.Runtime.Serialization.Formatters
System.Runtime.Serialization.Formatters.Binary
System.Security
System.Security.Cryptography
System.Security.Cryptography.X509Certificates
System.Security.Permissions
System.Security.Policy
System.Security.Principal
System.Text
System.Threading
System.Web
System.Web.Caching
System.Web.Configuration
System.Web.Handlers
System.Web.Hosting
System.Web.Mail
System.Web.Security
System.Web.SessionState
System.Web.UI
System.Web.UI.HtmlControls
System.Web.UI.WebControls
System.Web.Util
System.Xml
In the web.config file, within
the configSections tags, we have added the name ClassBrowser and specified the
type of information that it will contain. Thereafter, all the data is inserted
within the ClassBrowser tag. The data within this tag is in the key-value pair
format. It is always a good idea to store all the data in a file, and then read
this file at runtime. How we exploit these key-value pairs, will be
substantiated in the ASP+ program, whose explanation follows.
In a.aspx, we commence with the usual
suspect, the import namespaces command. An instance variable named ModuleName
of type ArrayList is initially created outside all the functions. It is done to
enable apportioning and sharing of this type ArrayList by all functions. In our
example, this ArrayList will store strings.
In the function Page_Load that
gets called at the server end, initially a variable named ConfigSettings is
created, which is an instance of a NameValueCollection class. A
NameValueCollection class stores the key-value pairs in an efficient way, so
that retrieval of the values is more rapid compared to an ArrayList. The
principal advantage of this is that we can effectively figure out whether a
key-value pair entry already exists or not.
In the aspx file, it is our
intention to access all the key-value pairs that are defined within the
ClassBrowser tag in the configuration file. The Context property in the Page
class, returns an HttpContext object. This Object has a function called
GetConfig, whose only task is to return the configuration of the name supplied
as a parameter. The Object returned by this function is then cast into a
NameValueCollection.
In order to verify that the
values have been actually placed, we display the Count member of the
NameValueCollection object. We see a value of 3, since we have 3 key-value
pairs in the ClassBrowser tag, within the web.config file.
<add key="Data
Library" value="System.Data" />
<add
key="ASP.NET Class Library" value="System.Web" />
<add
key=".NET Framework class Library" value="mscorlib" />
To display the values contained
in the web.config file, the for loop is used thrice, to iterate through all the
3 values.
In the loop, we add the variable
ModuleName to the ArrayList, with the values retrieved from the web.config
file. At the conclusion of the execution of the for loop, the ArrayList
contains the names of the 3 modules or dll's, whose details are to be
displayed. These details include the namespaces contained in them, the classes
in the namespaces, et al. You may recall that, the System.Web.dll contains all
the Web classes that we have been working on.
The ArrayList now holds the three
module names. Hence, the for loop iterates thrice. The class called Assembly in
the namespace System.Reflection has a static function named Load, which accepts
the name of a module and loads it into memory. The module gets loaded into the
address space of the program that is running this function, and returns an
Assembly object that represents the assembly. The function GetModules in the
assembly class returns an array of modules that are currently present in the
assembly.
In our program, CorRuntime, which
is an array variable of type Module, contains the modules in the assembly. An
assembly can easily contain more than one module, the first module being the
most significant, at the moment. This module object returns the number of types
using the GetTypes function. We store the types in the CorClasses array
variable of type Types. Thus, the hierarchy is assembly, modules and then, types.
The output very unambiguously
conveys to us the following:
• System.Web assembly has 1 module and
663 types.
• System.Data assembly has 1 module
and 427 types.
• mscorlib has 1 module and 1410
types.
Within the for loop, we add one
more for loop for every type, because we intend to include all the unique
namespaces from the assemblies in the ArrayList called NameSpaceList. The
crucial word in the above statement is 'unique'. The Add function in HashTable
and ArrayList is used to add the namespace in NameSpaceHash and the
NameSpaceList object respectively. If we stop at this stage, the list will
contain duplicate Namespaces. Hence, we first employ the ContainsKey function
to check whether the namespace is already added or not. If it does, then the namespaces are not
added again. ContainsKey returns true if a name already exists. The property
IsPublic is employed to discover whether the type of the namespace is public or
not.
Thus, namespaces marked public in
the assembly, are added only if they don't already exist in the list. The Type
class has a member called Namespace that returns the namespace that the type
belongs to. A type is a synonym for a class or interface, etc.
The array list is then sorted and
assigned to the DataSource member of the DataList called Namespace1. Finally,
using the DataBind function, a list of namespaces is displayed.
In our presentation logic, our
DataList Namespace1 now contains a list of namespaces. The template is executed
for each item in the DataList. However, the template named headertemplate is
executed only once, thereby, showing the word Namespaces only once in the
window. It is the template named itemtemplate that is called thrice. The
HyperLink tag displays the namespaces like a URL. A URL is generated each time
we click on a link. This URL is decided by the NavigateUrl property and looks
like http://localhost/a.aspx?namespace=Microsoft.Win32 . This is so because the
Container.DataItem contains the namespace name that we clicked on, and the
?namespace is given as a literal. The Text property displays the name of the
namespace. Also, the items that we have selected in the past, will be displayed
as per the template named selecteditemtemplate. This template displays the
namespace name in a bold tag.
Let us proceed to the next
example, where we propose to display a list of classes belonging to the
namespace.
a.aspx
<%@ Import NameSpace="System.Collections" %>
<%@ Import NameSpace="System.Reflection" %>
<html>
<head>
<script runat="server" language="C#">
public String SelectedNameSpace;
public ArrayList ModuleName = new ArrayList();
void Page_Load(Object Sender, EventArgs e)
{
NameValueCollection ConfigSettings = new
NameValueCollection();
ConfigSettings = (NameValueCollection)Context.GetConfig("system.web/ClassBrowser");
for (int i = 0; i < ConfigSettings.Count; i++)
{
ModuleName.Add(ConfigSettings[i].ToString());
}
DisplayNamespaces();
if (Request.QueryString["namespace"] == null)
SelectedNameSpace = "System";
else
SelectedNameSpace = Request.QueryString["namespace"];
if (Request.QueryString["class"] != null)
DisplayClass(Request.QueryString["class"]);
else
DisplayClassList(SelectedNameSpace);
}
private void DisplayNamespaces()
{
ArrayList NameSpaceList
= new ArrayList();
Hashtable NameSpaceHash = new Hashtable();
for (int y = 0; y < ModuleName.Count; y++) {
Module[] CorRuntime =
Assembly.Load(ModuleName[y].ToString()).GetModules();
Type[] CorClasses = CorRuntime[0].GetTypes();
for( int x=0; x < CorClasses.Length; x++ ) {
if ( CorClasses[x].Namespace != null )
{
if (!NameSpaceHash.ContainsKey(CorClasses[x].Namespace)
&& CorClasses[x].IsPublic ) {
NameSpaceHash.Add(CorClasses[x].Namespace,"");
NameSpaceList.Add(CorClasses[x].Namespace);
}
}
}
}
NameSpaceList.Sort();
Namespace1.DataSource = NameSpaceList;
Namespace1.DataBind();
}
private void DisplayClassList (String CurrentNameSpace)
{
ArrayList ClassList =
new ArrayList();
ArrayList InterfaceList = new ArrayList();
for( int y=0; y < ModuleName.Count; y++ ) {
Module[] CorRuntime =
Assembly.Load(ModuleName[y].ToString()).GetModules();
Type[] CorClasses = CorRuntime[0].GetTypes();
for (int x=0; x < CorClasses.Length; x++ ) {
if ( CorClasses[x].Namespace == CurrentNameSpace &&
CorClasses[x].IsPublic) {
if ( CorClasses[x].IsInterface )
InterfaceList.Add(CorClasses[x].Name);
else
ClassList.Add(CorClasses[x].Name);
}
}
}
if (InterfaceList.Count > 0)
IHeader.Visible = true;
if (ClassList.Count > 0)
CHeader.Visible = true;
ClassList.Sort();
Classes.DataSource = ClassList;
Classes.DataBind();
InterfaceList.Sort();
Interfaces.DataSource = InterfaceList;
Interfaces.DataBind();
}
private void DisplayClass(String className)
{
}
public String GetUrl(Hashtable table) {
return "a.aspx?namespace=" +
table["Namespace"] + "&class=" +
table["GetType"];
}
</script>
</head>
<body>
<form runat="server">
<table>
<td width=25% bgcolor=#CCCCFF valign=top >
<br>
<asp:DataList runat=server id="Namespace1"
RepeatLayOut="flow">
<headertemplate>
Namespaces <br>
</headertemplate>
<itemtemplate>
<asp:HyperLink runat="server" text=<%#
Container.DataItem %> NavigateUrl=<%# "a.aspx?namespace=" +
Container.DataItem %> />
</itemtemplate>
<selecteditemtemplate>
<b>
<asp:HyperLink runat=server text=<%# Container.DataItem
%>/>
</b>
</selecteditemtemplate>
</asp:DataList>
<p>
<td valign=top >
<span runat=server id="CHeader"
visible="false" style="text-indent:8">
<b>
<font size=4 color=#000666>Classes in
<%= SelectedNameSpace %>
</b>
</font>
</span>
<asp:DataList EnableViewState="false" runat=server
id="Classes" RepeatColumns="3" Gridlines=None
borderstyle=none borderwidth=0 >
<itemtemplate>
<asp:HyperLink runat=server text=<%# Container.DataItem
%> NavigateUrl=<%# "a.aspx?namespace=" + SelectedNameSpace +
"&class=" + Container.DataItem %> />
</itemtemplate>
</asp:DataList>
<span runat=server id="IHeader"
visible="false" style="text-indent:8">
<b>
<font size=4 color=#000666>Interfaces in <%=
SelectedNameSpace %>
</font>
</b>
</span>
<asp:DataList EnableViewState="false" runat=server
id="Interfaces" RepeatColumns="4" Gridlines=None
borderstyle=none borderwidth=0 >
<itemtemplate>
<asp:HyperLink runat=server
text=<%# Container.DataItem %> NavigateUrl=<%#
"a.aspx?namespace=" + SelectedNameSpace + "&class=" +
Container.DataItem %>/>
</itemtemplate>
</asp:DataList>
</form>
</body>
</html>
In the above program, two panes
are displayed. The pane on the left hand side has a list of namespaces, while
the pane on the right hand side contains a list of classes in the Systems
namespace. If you click on any of the namespaces, the classes displayed in the
right pane will change correspondingly. The URL generated reads as follows:
http://localhost/a.aspx?namespace=Microsoft.Win32.
We shall only explain the extra
lines of code that have been added to the program, to display in the right
pane, only those classes that are contained in a specific namespace.
The DisplayNamespaces function
has not been altered. It displays the namespaces contained in the three dlls.
Thereafter, we verify if the namespace variable contains any value. Similar to
the functioning of Request.QueryString, here also it is assumed that the form
is reloaded with the namespace variable containing a value. Since we have
loaded the file for the first time, the namespace parameter does not come into
existence. Hence, the string variable named SelectedNameSpace is initialized to
System. It is for this reason that we see the classes belonging to the System
namespace, at startup.
Since we do not have a parameter
called class with our URL, the next function to be called is DisplayClassList.
This function displays a list of classes belonging to the namespace name, which
is currently stored in SelectedNamespace.
In the DisplayClassList function,
two ArrayList objects named ClassList and InterfaceList are created. ClassList
holds the list of classes and InterfaceList holds the list of interfaces. As
always, we go through the rigmarole of fetching each and every type, just as we
did earlier, and then checking whether the class or type belongs to the
namespace specified in the parameter named CurrentNameSpace. If it is so, then
using the IsInterface property, we determine whether the type is a class or an
interface, as follows:
• If the IsInterface property returns
a value of true, it means that the type is an interface. Hence, it gets added to
the InterfaceList.
• If the IsInterface property returns
a value of false, it means that the type is a class. Hence, it gets added to
the ClassList.
Once the ArrayLists have been
filled up, we determine the number of entries in them, using their Count
member. If the value returned by Count in the Interface List is greater than
zero, the visible property of a span IHeader is set to true. In this situation,
the static text 'Interfaces in' is displayed, followed by the name of the
namespace, in a bold format. The same procedure is repeated for the ClassList
also. A span is useful when many items have to be placed together, because all
of them can be manipulated as a single item.
Finally, we have two more
DataList objects named Classes and Interfaces. Their DataSource members are
initialized to the list of classes and interfaces stored in the two ArrayList
objects named ClassList and InterfaceList, respectively.
Thus, as you can see in the above
program, we have created an ArrayList and filled it up with data. Then, we
request the DataSource property of some DataList to display it.
The output in the browser should
show the namespaces and the list of classes, concurrently. This can be
accomplished only by means of a table. So, we have a table tag containing two
table columns.
The first table column called td
has a background color and occupies 25% of the table width. This ensures that
the first DataList is in one column.
In the next td, the names of the
classes and the interfaces are displayed side by side.
The template itemtemplate is
repeated for all the classes in the DataSource. Each class name is displayed as
a hyperlink, and the URL that is required to navigate to it, contains the
following:
• the file name a.aspx.
• the name of the namespace.
• the name of the class given to
parameters namespace and class.
http://localhost/a.aspx?namespace=System.Collections&class=ArrayList
The same process is repeated for
the interfaces.
Let us now attempt to display the
list of functions in a class.
a.aspx
<%@ Import NameSpace="ClassInfo" %>
<%@ Import NameSpace="System.Collections" %>
<%@ Import
NameSpace="System.Collections.Specialized" %>
<%@ Import NameSpace="System.Reflection" %>
<html>
<head>
<script runat="server" language="C#">
public String SelectedAssembly;
public String SelectedNameSpace;
public ArrayList ModuleName = new ArrayList();
protected void Page_Load(Object Sender, EventArgs e) {
NameValueCollection ConfigSettings =
(NameValueCollection)Context.GetConfig("system.web/ClassBrowser");
for (int i = 0; i < ConfigSettings.Count; i++)
ModuleName.Add(ConfigSettings[i].ToString());
DisplayNamespaces();
if (Request.QueryString["namespace"] == null)
SelectedNameSpace =
"System";
else
SelectedNameSpace =
Request.QueryString["namespace"];
if (Request.QueryString["assembly"] == null )
SelectedAssembly =
"mscorlib";
else
SelectedAssembly =
Request.QueryString["assembly"];
if (Request.QueryString["class"] != null &&
Request.QueryString["assembly"] != null)
DisplayClass(Request.QueryString["assembly"],
Request.QueryString["class"]);
else
DisplayClassList(SelectedNameSpace);
}
private void DisplayNamespaces() {
ArrayList NameSpaceList
= new ArrayList();
Hashtable NameSpaceHash = new Hashtable();
for (int y = 0; y < ModuleName.Count; y++) {
Module[] CorRuntime =
Assembly.Load(ModuleName[y].ToString()).GetModules();
Type[] CorClasses =
CorRuntime[0].GetTypes();
for( int x=0; x < CorClasses.Length; x++ )
{
if ( CorClasses[x].Namespace != null )
{
if (!NameSpaceHash.ContainsKey(CorClasses[x].Namespace)
&& CorClasses[x].IsPublic ) {
NameSpaceHash.Add(CorClasses[x].Namespace,"");
NameSpaceList.Add(CorClasses[x].Namespace);
}
}
}
}
NameSpaceList.Sort();
Namespace1.DataSource = NameSpaceList;
Namespace1.DataBind();
}
private void DisplayClassList(String CurrentNameSpace) {
ArrayList ClassList =
new ArrayList();
ArrayList InterfaceList = new ArrayList();
for( int y=0; y < ModuleName.Count; y++ ) {
Module[] CorRuntime =
Assembly.Load(ModuleName[y].ToString()).GetModules();
Type[] CorClasses =
CorRuntime[0].GetTypes();
for (int x=0; x < CorClasses.Length; x++ )
{
if (
CorClasses[x].Namespace == CurrentNameSpace && CorClasses[x].IsPublic)
{
SortTable props = new SortTable("GetType");
props["GetType"] = CorClasses[x].Name;
props["Namespace"] = CorClasses[x].Namespace;
props["Assembly"]=
CorClasses[x].Assembly.GetName().Name;
if ( CorClasses[x].IsInterface )
InterfaceList.Add(props);
else
ClassList.Add(props);
}
}
}
if (InterfaceList.Count > 0)
IHeader.Visible = true;
if (ClassList.Count > 0)
CHeader.Visible = true;
ClassList.Sort();
Classes.DataSource =
ClassList;
Classes.DataBind();
InterfaceList.Sort();
Interfaces.DataSource =
InterfaceList;
Interfaces.DataBind();
}
private void DisplayClass(String asmName, String className) {
Assembly a =
Assembly.Load(asmName);
Type ClassType =
a.GetType(SelectedNameSpace.ToString() + "." + className, false,
true);
if ( ClassType == null ) {
DisplayClassList(SelectedNameSpace);
return;
}
DisplayMethods MethodDetails
= new DisplayMethods(ClassType,
className);
if(MethodDetails.Count
!= 0 )
Methods.DataSource
= MethodDetails;
DataBind();
if
(ClassType.IsInterface)
spnClassName.InnerHtml = "Interface " + SelectedNameSpace +
"." + className;
else
spnClassName.InnerHtml
= "Class " + SelectedNameSpace + "." + className;
NameSpacePanel.Visible=false;
ClassPanel.Visible=true;
}
public String GetUrl(Object
objTable) {
if ( objTable is
String ) {
return
"a.aspx?assembly=" + SelectedAssembly + "&namespace=" +
SelectedNameSpace + "&class=" + objTable;
}
if ( ! (objTable
is Hashtable) ) {
Response.Write(objTable.GetType().ToString());
Response.End();
}
Hashtable table =
(Hashtable) objTable;
return
"a.aspx?assembly=" + table["Assembly"] +
"&namespace=" + table["Namespace"] +
"&class=" + table["GetType"];
}
</script>
</head>
<body>
<form
runat="server">
<table>
<tr>
<td width=25%
bgcolor=#CCCCFF valign=top >
<br>
<asp:DataList
EnableViewState="false" runat=server id="Namespace1"
RepeatLayOut="flow">
<HeaderTemplate>Namespaces <br> </HeaderTemplate>
<ItemTemplate>
<asp:HyperLink runat="server" text=<%#
Container.DataItem %> NavigateUrl=<%# "a.aspx?namespace=" +
Container.DataItem %> />
</ItemTemplate>
<SelectedItemTemplate>
<b><asp:HyperLink
runat=server text=<%# Container.DataItem %>/></b>
</SelectedItemTemplate>
</asp:DataList>
<p>
</td>
<td valign=top
>
<div
id="ClassPanel" style="margin-top:15;margin-left:10"
visible="false" runat="server">
<b><font size=4 color="000666"><span
style="text-indent:8" id="spnClassName"
EnableViewState="false"
runat="server"/></font></b>
</div>
<div id="NameSpacePanel"
runat="server">
<table class="main" width=100%>
<tr>
<td class="main_header">
<span runat=server id="CHeader"
visible="false" style="text-indent:8"> <b><font
size=4 color=#000666>Classes in
<%= SelectedNameSpace %>
</b> </font></span>
</td> </tr>
<tr>
<td align="left">
<asp:DataList EnableViewState="false" runat=server
id="Classes" RepeatColumns="3" Gridlines=None
borderstyle=none borderwidth=0>
<ItemTemplate>
<asp:HyperLink runat=server text=<%# ((SortTable)
Container.DataItem)["GetType"] %> NavigateUrl=<%# GetUrl(Container.DataItem)
%> />
</ItemTemplate>
</asp:DataList>
</td>
</tr>
</table>
<table class="main" width=100% >
<tr>
<td class="main_header" >
<span runat=server id="IHeader"
visible="false" style="text-indent:8"> <b>
<font size=4 color=#000666>Interfaces in <%
=SelectedNameSpace %> </font>
</b> </span>
</td>
</tr>
<tr>
<td align="left">
<asp:DataList EnableViewState="false" runat=server
id="Interfaces" RepeatColumns="4" Gridlines=None
borderstyle=none borderwidth=0>
<ItemTemplate>
<asp:HyperLink runat=server
text=<%# ((SortTable) Container.DataItem)["GetType"] %>
NavigateUrl=<%# GetUrl(Container.DataItem) %>/>
</ItemTemplate>
</asp:DataList>
</td>
</tr>
</table>
</div>
<p>
<asp:DataList EnableViewState="false"
id="Methods" runat="server"
Gridlines=None borderstyle="none"
borderwidth="0" width="100%">
<HeaderTemplate>
<table cellspacing=0
>
<tr><td
class="class_header"><b><font size=2> Methods
</font></b></td></tr>
<tr bgcolor="eeeeee">
<td width="75"
><b><u>Visibility</td>
<td width="100"><b><u>Return
</td>
<td width="100"><b><u>Name</td>
<td
width="600"><b><u>Parameters</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr bgcolor="eeeeee">
<td
width="75"><nobr><span runat=server
InnerHtml=<%# ((SortTable)
Container.DataItem)["Access"]%> /></nobr></td>
<td width="100">
<asp:HyperLink runat=server NavigateUrl=<%#
GetUrl(Container.DataItem) %> text=<%# ((SortTable)
Container.DataItem)["Type"]%>/>
</td>
<td width="100"><span runat=server
InnerHtml=<%# ((SortTable)
Container.DataItem)["Name"]%>/></td>
<td
width="900">
<asp:DataList EnableViewState="false" runat=server
datasource=<%# ((SortTable)
Container.DataItem)["Params"] %>
RepeatLayout=Flow RepeatDirection="Horizontal"
showfooter=true >
<HeaderTemplate>
(
</HeaderTemplate>
<ItemTemplate>
<asp:HyperLink text=<%# ((SortTable)
Container.DataItem)["ParamType"].ToString() %> NavigateUrl=<%#
GetUrl(Container.DataItem) %> runat=server />
<span InnerHtml=<%# ((SortTable)
Container.DataItem)["ParamName"] %> runat=server />
</ItemTemplate>
<SeparatorTemplate> ,</SeparatorTemplate>
<FooterTemplate> ) </FooterTemplate>
</asp:DataList>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:DataList>
<p><p>
<asp:DataList EnableViewState="false"
id="Interface1" runat=server style="margin-left:10"
RepeatDirection="horizontal"
RepeatLayout="Flow"
width="100%">
<HeaderTemplate>
<font size=2><b> Implements </b></font>
<br>
</HeaderTemplate>
<ItemTemplate>
<asp:HyperLink runat=server NavigateUrl=<%#
GetUrl(Container.DataItem) %> text=<%# ((SortTable)
Container.DataItem)["FullName"]%> />
</ItemTemplate>
<SeparatorTemplate>
<font face="Verdana"
style="font-size:8pt">,
</SeparatorTemplate>
</asp:DataList>
<p>
<p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
</body>
</html>
b.cs
using System ;
using System.Web;
using System.Web.UI;
using System.Collections;
using System.Reflection;
namespace ClassInfo {
public class SortTable : Hashtable, IComparable {
public String sortField;
public SortTable() : this(null) {
}
public SortTable(String sField) {
sortField = sField;
}
public int CompareTo(Object b) {
if ( sortField == null ) {
return 0;
}
return
((String)this[sortField]).CompareTo((String)((SortTable)b)[sortField]);
}
}
public class DisplayMethods : ArrayList {
public DisplayMethods(Type classType, String myclassname) {
System.Reflection.MethodInfo[] methodInfos =
classType.GetMethods() ;
if (methodInfos == null)
return;
for (int x=0; x<methodInfos.Length; x++) {
if((String.Compare(myclassname,methodInfos[x].DeclaringType.Name
)==0)&&(methodInfos[x].IsPublic || methodInfos[x].IsFamily) &&
(!(methodInfos[x].IsSpecialName)) ) {
SortTable MethodDetails =
new SortTable("Name");
MethodDetails["Assembly"] =
methodInfos[x].GetType().Assembly.GetName().Name;
MethodDetails["Name"] = methodInfos[x].Name;
MethodDetails["Type"] = methodInfos[x].ReturnType.Name;
if((
methodInfos[x].ReturnType.IsArray && methodInfos[x].ReturnType.Name
!="Array") ||
methodInfos[x].ReturnType.IsPointer) {
Type ReturnElementType =
methodInfos[x].ReturnType.GetElementType();
while(ReturnElementType.IsArray) {
ReturnElementType =
ReturnElementType.GetElementType();
}
MethodDetails["GetType"] = ReturnElementType.Name ;
MethodDetails["Namespace"] =
ReturnElementType.Namespace ;
} else {
MethodDetails["GetType"] =
methodInfos[x].ReturnType.Name;
MethodDetails["Namespace"] =
methodInfos[x].ReturnType.Namespace ;
}
if (methodInfos[x].IsPublic == true) {
MethodDetails["Access"] = "public ";
} else if (methodInfos[x].IsPrivate == true) {
MethodDetails["Access"] = "private ";
} else if (methodInfos[x].IsFamily == true) {
MethodDetails["Access"] = "protected ";
}
if (methodInfos[x].IsStatic == true) {
MethodDetails["Access"] = ((String)
MethodDetails["Access"]) + "static ";
}
System.Reflection.ParameterInfo[] paramInfos =
methodInfos[x].GetParameters();
if (paramInfos != null) {
ArrayList paramTable = new ArrayList();
for (int y=0; y<paramInfos.Length; y++) {
SortTable paramDetails = new SortTable();
paramDetails["Assembly"] = paramInfos[y].GetType().Assembly.GetName().Name;
paramDetails["ParamName"] = paramInfos[y].Name;
paramDetails["ParamType"] =
paramInfos[y].ParameterType.Name;
if(( paramInfos[y].ParameterType.IsArray && paramInfos[y].ParameterType.Name
!= "Array" ) ||
paramInfos[y].ParameterType.IsPointer) {
paramDetails["GetType"] = paramInfos[y].ParameterType.GetElementType().Name ;
paramDetails["Namespace"] =
paramInfos[y].ParameterType.GetElementType().Namespace ;
} else {
paramDetails["GetType"] = paramInfos[y].ParameterType.Name;
paramDetails["Namespace"] =
paramInfos[y].ParameterType.Namespace ;
}
paramTable.Add(paramDetails);
}
MethodDetails["Params"] = paramTable;
}
this.Add(MethodDetails);
}
}
this.Sort();
}
}
}
To run the above program, you
need to first place the file b.cs in the sub-directory c:\inetpub\wwwroot\bin
and compile it as follows:
>csc /target:library b.cs
When a.aspx is loaded in the
browser, the list of namespaces is displayed on the left, and the list of
classes belonging to the System namespace is seen on the right. If you click on
any class, a list of functions belonging to that class will be displayed. The
data is displayed in a tabular format in four columns.
• The first column represents the
visibility. The values contained in it, are either public, or private or
protected.
• The second column indicates the
return data type.
• The third column displays the names
of the functions.
• The fourth column holds the
parameters with their names and data types.
All types are hyper linked, so
when we click on any one of them, a screen comes forth, displaying the
functions or methods that the specified type supports.
When we click on the name of a
class, the following URL gets generated:
http://localhost/a.aspx?assembly=mscorlib&namespace=System&class=Exception
The Page_Load function calls the
DisplayClass function, since the class and the assembly parameter contains a
value. This proves that the DisplayClassList function is called only in the
first round, while loading the page.
In the DisplayClass function, we
first need the type of the object. The static function called GetType,
belonging to the Type class, returns a type when it is supplied with the full
name of the class. So, we concatenate the namespace name stored in the instance
variable SelectedNameSpace, with the parameter className, and then pass the
full name to this function. The Type returned by the GetType function is stored
in a variable called ClassType.
Next, we create an object called
MethodDetails of type DisplayMethods, which requires two parameters, the Type
and the className. DisplayMethods is, in turn, derived from the class
ArrayList. The ArrayList object named MethodDetails, obviously contains the
details about the methods. Using the Count member, we can determine the total
number of methods in the class. If the value returned is greater than 0, we
initialize the DataSource member called Methods, of the DataList, to this
ArrayList. The span control called spnClassName, then displays the name of the
namespace and that of the class.
We have two div tags having the
ids ClassPanel and NameSpacePanel. Their visible property is set to either true
or false, thereby, ensuring that all the div contents are either displayed or
hidden from view. In the DisplayClass, we have hidden the data contained within
these tags by setting the Visible property to false. Thus, in one stroke, we
can conceal or reveal a large number of entities. These tags are extremely
useful because our browser's real estate is restricted, and we do not have the
space to display everything.
Let us now scrutinize the
presentation logic. As we mentioned earlier, the DataList called Methods
displays all the method names neatly formatted. You may have been ambushed by
the revelation that a simple DataList was able to display everything. The
template named headertemplate is called once, to display the four column
headers of the table. The table tag does not end with the template, as each
method is now displayed as a table row. The bold and underline tags have been
provided to produce visually stunning output.
The DisplayMethods class uses the
indexer method to retrieve the values of the Visible and Type members. Thus, in
the span tag, we use the array syntax to display the Access and Type members.
The function GetUrl navigates to the relevant type by creating a URL, followed
by the parameters called assembly, namespace and class, filled up with relevant
values. From the browser's point of view, it does not make any difference
whether we click on the class name in the first screen or in the second one.
Life is not very straightforward
now, since we have made an endeavor to display the parameters of the method,
which could number from nil to infinity. In order to achieve this, we create
another DataList within the Methods DataList and initialize the DataSource
parameter to the Params value in the DisplayMethods object. To display the
parameters, a template with a hyper link is utilized. It shows the data type or
ParamType as a hyperlink. The URL to this link is generated by the GetUrl
function. The ParamName is displayed as normal text.
The whole code is enclosed in
open and close brackets, and is available in the headertemplate and
footertemplate. The template named separatortemplate supplies the commas to
separate the individual parameter names and values. To summarize, we are using
a nested DataList to display an array of values within another array.
We have a confession to make at
this juncture. The class named DisplayMethods has not been supplied by
Microsoft. It is created in the file b.cs. This class is derived from ArrayList
and gives us all the details of every method that exists in a type.
Let us now focus on the class
DisplayMethods in the file b.cs.
This is a perfect example of a
two-tier illustration, where the presentation logic is placed in one file, and
the C# code that handles Reflection, is placed in another file.
The class DisplayMethods has to
extend the ArrayList class, because in the aspx file, we are initializing the
DataSource member of the Methods DataList to this data type. Also, the
constructor in the DisplayClass
function has been supplied with two parameters, namely, the Type and className.
DisplayMethods MethodDetails= new
DisplayMethods(ClassType, className);
There exists a static method
called GetMethods in the Type class, that returns a MethodInfo array. The
methodInfos array reveals every aspect of the function. No parameter is
supplied indicating that the default rules are to be applied when locating a
function. In case there are no methods available in a class, a null value is
stored in the array variable.
The Length member of the array
stores a count of the number of methods contained in the array. Thereafter,
using a for loop we iterate through each and every method. A 'foreach' loop
could also be used to achieve the same functionality. In the loop, we use a
Compare function of the String class, to verify the validity of the method. The
property DeclaringType returns a Type or the class that consists of this
method. Type in turn, has a property called Name, that represents the name of
the class. Compare takes this name and checks it with the parameter
myclassname, which is a parameter passed to the constructor. It is just an
additional check.
We also ensure that the method is
public or it belongs to the family (current of derived class) that can access
it. The compiler treats functions that possess special names, differently. For
example, the constructor is given a special name, i.e. .ctor. These methods are
not to be included in our list of methods, and hence, the ! sign is used. The
method must successfully pass all the above conditions, or else, it will not be
incorporated as a part of the methods list that is returned.
On passing the above test, the
next task is to gain access to the template in the aspx file. To accomplish
this, an indexer or an array is employed. It returns an object that is an
instance of a Hashtable. For the ones who walked in late, the Hashtable class
lets us access data in an efficient manner, and also offers us an indexer
support.
MethodDetails is an instance of
the SortTable class, which consecutively extends the class Hashtable. The
single parameter constructor of the SortTable is called using the Name
parameter. The constructor stores the value contained in the Name variable, in
a public variable called sortField. Thereafter, using the indexer features of
the Hashtable class, the following is achieved:
• The name of the assembly is stored
in an indexer variable called Assembly.
• The name of the method is stored in
an indexer variable called Name.
• The name of the return type is
stored in the indexer variable called Type.
The name of the return type or
class is obtained as follows:
The MethodInfo class has a
property called ReturnType that returns the Type of the return value. The Type
in turn, has a member called Name that holds the name of the Type.
There are instances where a
multi-dimension array or a pointer is returned. These being exceptional cases,
separate 'if 'statements are required to handle them. First, using the property
IsArray, the name property in ReturnType is checked. If the name contains the
word 'Array' or the ReturnType is a pointer, we can safely conclude that the
function returns a Multi-Dimensional array. So, we use the function
GetElementType in ReturnType, to return the Type of the object encompassed, or
referenced by either an array, or a pointer, or by ByRef.
The predicament with arrays is
that their dimensions could range from 2 to infinity, which could put us in a
tight spot. To tide over this situation, we use a loop construct like a while
or a for loop. Thus, using IsArray, we keep looping, until the Type becomes an
array. All arrays, multi-dimensional or otherwise, have a Type name. Ignoring the
fact that it is an array, we initialize the indexer variable GetType to this
Type name, and initialize the namespace variable to the namespace of this type.
This course of action is essential if we aspire to display the final data type
of the array.
Under normal circumstances, the
return type is generally a Type object. In such cases, we can use the same Name
and Namespace properties to retrieve its value and store it in the MethodDetail
Indexer.
The next task in sequence is to
store the access modifiers, which our function has been tagged with. We intend
to determine whether the method is public, private or protected. To achieve
this, we use the three properties named, IsPublic, IsPrivate and IsFamily.
Accordingly, the relevant access modifier is stored in the indexer variable
called Access. The function is also checked to establish if it is static. To
accomplish this, the property IsStatic is used. If it returns a value of true,
the string static is added to the Access indexer variable.
Now, we have arrived at a
relatively uncomplicated part.
The names and the data types of
the parameters have to be retrieved. The number of parameters to a function can
range from zero to infinity. We initialize an object called paramInfos by
calling the GetParameters function, which returns a ParameterInfo array. A
separate ArrayList is now required to store this variable set of data. So, we
create a separate ArrayList object called paramTable, which stores certain
information about the parameters, such as the name and type.
Depending upon the length of the
array, the loop is repeated a specific number of times, wherein, the Name
property of a ParameterInfo object, is assigned to an indexer variable called
ParamName. The ParameterInfo class also contains a property called
ParameterType, whose Type member holds the name of the Type. Thereafter, as
before, we check if the return type is a Multi-dimensional array. If so, the
final type of the Multi-Dimensional array is figured out. Eventually, the
GetType and Namespace are initialized from the normal types of the
multi-dimensional arrays, to the return type of the function and the namespace
of the type, respectively. Thereafter, this single record of paramDetails is
added to the paramTable ArrayList. This loop is repeated for every method in
the class. Once the loop terminates, the indexer variable Params in
MethodDetails, is initialized to the paramTable object.
Finally, the MethodDetails is
added to the ArrayList and the ArrayList is sorted. Sortng of the list is not
obligatory.
To recapitulate, the
MethodDetails class consists of multiple records that can be accessed through
an indexer, using parameter names like GetType and Namespace. The Params
parameter in the MethodDetail indexer is made up of another ArrayList, and has
members like ParamName and ParamType.
The interface IComparable attains
significance because it contains the CompareTo function from the string class.
Now, for the grand finale! We
shall delve upon the class browser application from the Microsoft Samples.
web.config
<configuration>
<configSections>
<sectionGroup name="system.web">
<section name="ClassBrowser"
type="System.Configuration.NameValueSectionHandler,System"/>
</sectionGroup>
</configSections>
<system.web>
<ClassBrowser>
<add key="WinForms Library"
value="System.Windows.Forms" />
<add key="Drawing Library"
value="System.Drawing" />
<add key="Data Library"
value="System.Data" />
<add key="Xml Library" value="System.Xml"
/>
<add key="Messaging Library"
value="System.Messaging" />
<add key="Directory Services Library"
value="System.DirectoryServices" />
<add key="ASP.NET Class Library"
value="System.Web" />
<add key=".NET Framework class Library"
value="mscorlib" />
</ClassBrowser>
</system.web>
</configuration>
a.aspx
<%@ Page Language="C#" Debug="True" %>
<%@ Import NameSpace="ClassInfo" %>
<%@ Import NameSpace="System.Collections" %>
<%@ Import
NameSpace="System.Collections.Specialized" %>
<%@ Import NameSpace="System.Reflection" %>
<html><head>
<script runat="server" language="C#">
public String
SelectedAssembly;
public String
SelectedNameSpace;
public ArrayList
ModuleName = new ArrayList();
protected void
Page_Load(Object Sender, EventArgs e) {
NameValueCollection
ConfigSettings = (NameValueCollection)Context.GetConfig("system.web/ClassBrowser");
for (int i = 0; i < ConfigSettings.Count; i++) {
ModuleName.Add(ConfigSettings[i].ToString());
}
DisplayNamespaces();
if (Request.QueryString["namespace"] == null)
SelectedNameSpace = "System";
else
SelectedNameSpace = Request.QueryString["namespace"];
if (Request.QueryString["assembly"] == null )
SelectedAssembly =
"mscorlib";
else
SelectedAssembly =
Request.QueryString["assembly"];
if (Request.QueryString["class"] != null &&
Request.QueryString["assembly"] != null)
DisplayClass(Request.QueryString["assembly"],
Request.QueryString["class"]);
else
DisplayClassList(SelectedNameSpace);
}
private void DisplayNamespaces() {
ArrayList
NameSpaceList = new ArrayList();
Hashtable
NameSpaceHash = new Hashtable();
for (int y = 0; y
< ModuleName.Count; y++) {
Module[] CorRuntime =
Assembly.Load(ModuleName[y].ToString()).GetModules();
Type[] CorClasses =
CorRuntime[0].GetTypes();
for( int x=0; x <
CorClasses.Length; x++ ) {
if (
CorClasses[x].Namespace != null ) {
if
(!NameSpaceHash.ContainsKey(CorClasses[x].Namespace) &&
CorClasses[x].IsPublic ) {
NameSpaceHash.Add(CorClasses[x].Namespace,"");
NameSpaceList.Add(CorClasses[x].Namespace);
}
}
}
}
NameSpaceList.Sort();
Namespace1.DataSource = NameSpaceList;
Namespace1.DataBind();
}
private void
DisplayClassList(String CurrentNameSpace) {
ArrayList ClassList = new ArrayList();
ArrayList
InterfaceList = new ArrayList();
for( int y=0; y <
ModuleName.Count; y++ ) {
Module[] CorRuntime =
Assembly.Load(ModuleName[y].ToString()).GetModules();
Type[] CorClasses = CorRuntime[0].GetTypes();
for (int x=0; x <
CorClasses.Length; x++ ) {
if (
CorClasses[x].Namespace == CurrentNameSpace && CorClasses[x].IsPublic)
{
SortTable props = new SortTable("GetType");
props["GetType"] = CorClasses[x].Name;
props["Namespace"] = CorClasses[x].Namespace;
props["Assembly"] = CorClasses[x].Assembly.GetName().Name;
if
( CorClasses[x].IsInterface )
InterfaceList.Add(props);
else
ClassList.Add(props);
}
}
}
if
(InterfaceList.Count > 0)
IHeader.Visible = true;
if
(ClassList.Count > 0)
CHeader.Visible = true;
ClassList.Sort();
Classes.DataSource = ClassList;
Classes.DataBind();
InterfaceList.Sort();
Interfaces.DataSource = InterfaceList;
Interfaces.DataBind();
}
private void
DisplayClass(String asmName, String className) {
Assembly a =
Assembly.Load(asmName);
Type ClassType
= a.GetType(SelectedNameSpace.ToString() + "." + className, false,
true);
if ( ClassType
== null ) {
DisplayClassList(SelectedNameSpace);
return;
}
ArrayList
SubClassDetails = new DisplaySubClasses(ClassType, ModuleName);
DisplayConstructors
ConstructorDetails = new
DisplayConstructors(ClassType);
DisplayFields
FieldDetails = new DisplayFields(ClassType);
DisplayProperties
PropertyDetails = new DisplayProperties(ClassType);
DisplayMethods
MethodDetails = new DisplayMethods(ClassType, className);
DisplaySuperclasses
SuperClassDetails = new DisplaySuperclasses(ClassType);
DisplayInterfaces
InterfaceDetails = new DisplayInterfaces(ClassType);
DisplayEvents
EventDetails = new DisplayEvents(ClassType);
if(ConstructorDetails.Count != 0 )
Constructors.DataSource = ConstructorDetails;
if(SubClassDetails.Count != 0 )
SubClasses.DataSource
= SubClassDetails;
if(FieldDetails.Count != 0 )
Fields.DataSource =
FieldDetails;
if(PropertyDetails.Count != 0 )
Properties.DataSource = PropertyDetails;
if(MethodDetails.Count != 0 )
Methods.DataSource =
MethodDetails;
if(InterfaceDetails.Count != 0 )
Interface1.DataSource = InterfaceDetails;
if(SuperClassDetails.Count != 0 )
SuperClasses.DataSource = SuperClassDetails;
if(EventDetails.Count != 0 )
Events.DataSource =
EventDetails;
DataBind();
if (ClassType.IsInterface)
spnClassName.InnerHtml =
"Interface " + SelectedNameSpace + "." + className;
else
spnClassName.InnerHtml =
"Class " + SelectedNameSpace + "." + className;
NameSpacePanel.Visible=false;
ClassPanel.Visible=true;
}
public String GetUrl(Object objTable) {
if ( objTable is String )
{
return
"a.aspx?assembly=" + SelectedAssembly + "&namespace=" +
SelectedNameSpace + "&class=" + objTable;
}
if ( ! (objTable is
Hashtable) ) {
Response.Write(objTable.GetType().ToString());
Response.End();
}
Hashtable table = (Hashtable)
objTable;
return
"a.aspx?assembly=" + table["Assembly"] +
"&namespace=" + table["Namespace"] +
"&class=" + table["GetType"];
}
</script>
</head>
<body>
<form
runat="server">
<table width=100%
height=700 cellpadding=0 cellspacing=0>
<tr>
<td width=25%
bgcolor=#CCCCFF valign=top > <br>
<asp:DataList
EnableViewState="false" runat=server id="Namespace1"
RepeatLayOut="flow" ItemStyle-Font-Size="9pt"
HeaderStyle-Font-Size="12pt" >
<HeaderTemplate>
<div left-margin="10"> Namespaces <br>
</HeaderTemplate>
<ItemTemplate>
<asp:HyperLink runat="server" text=<%#
Container.DataItem %> NavigateUrl=<%# "a.aspx?namespace=" +
Container.DataItem %> />
</ItemTemplate>
<SelectedItemTemplate>
<b><asp:HyperLink
runat=server text=<%# Container.DataItem %>/></b>
</SelectedItemTemplate>
</asp:DataList>
<p>
</td>
<td valign=top >
<div
id="ClassPanel" style="margin-top:15;margin-left:10"
visible="false" runat="server">
<b><font size=4
color="000666"><span style="text-indent:8"
id="spnClassName" EnableViewState="false"
runat="server"/></font></b>
</div>
<div
id="NameSpacePanel" runat="server">
<table
class="main" width=100%>
<tr>
<td class="main_header">
<span runat=server
id="CHeader" visible="false"
style="text-indent:8"> <b><font size=4
color=#000666>Classes in
<%=
SelectedNameSpace %> </b>
</font></span>
</td>
</tr>
<tr>
<td
align="left">
<asp:DataList EnableViewState="false" runat=server
id="Classes" RepeatColumns="3" Gridlines=None
borderstyle=none borderwidth=0 >
<ItemTemplate>
<asp:HyperLink runat=server text=<%# ((SortTable)
Container.DataItem)["GetType"] %> NavigateUrl=<%# GetUrl(Container.DataItem)
%> />
</ItemTemplate>
</asp:DataList>
</td>
</tr>
</table>
<table class="main" width=100% >
<tr>
<td class="main_header" >
<span runat=server id="IHeader"
visible="false" style="text-indent:8"> <b><font
size=4 color=#000666>Interfaces in
<%= SelectedNameSpace
%> </font> </b>
</span>
</td>
</tr>
<tr>
<td align="left">
<asp:DataList EnableViewState="false" runat=server
id="Interfaces" RepeatColumns="4"
Gridlines=None borderstyle=none borderwidth=0 >
<ItemTemplate>
<asp:HyperLink runat=server
text=<%# ((SortTable) Container.DataItem)["GetType"] %>
NavigateUrl=<%# GetUrl(Container.DataItem) %>/>
</ItemTemplate>
</asp:DataList>
</td>
</tr>
</table>
</div>
<table
class="main" width=100% cellpadding=0 cellspacing=0 >
<tr>
<td
class="main_header" valign="top" >
<asp:DataList EnableViewState="false"
id="Constructors" runat="server" Gridlines=None
borderstyle="none" borderwidth=0
width="100%">
<HeaderTemplate>
<table cellspacing=0 width="100%">
<tr><td class="class_header"><b><font
size=2> Constructors </font></b></td></tr>
<tr bgcolor="eeeeee">
<td width="75" > <b><u> Visibility </u> </td>
<td width="100"> <b><u> Constructor </u> </td>
<td>
<b><u> Parameters
</u> </td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr
bgcolor="eeeeee">
<td width="75">
<span runat=server InnerHtml=<%# ((SortTable)
Container.DataItem)["Access"] %> />
</td>
<td width="100">
<span runat=server InnerHtml =<%# ((SortTable) Container.DataItem)["Name"]
%> />
</td>
<td width="1000">
<asp:DataList
EnableViewState="false"
runat=server
RepeatDirection="Horizontal"
RepeatLayout=Flow
showfooter=true datasource=<%# ((SortTable)
Container.DataItem)["Params"]%> >
<HeaderTemplate> ( </HeaderTemplate>
<ItemTemplate>
<asp:HyperLink text=<%# ((SortTable)
Container.DataItem)["ParamType"] %> NavigateUrl=<%#
GetUrl(Container.DataItem) %> runat=server />
<span innerhtml=<%# ((SortTable)
Container.DataItem)["ParamName"] %> runat=server />
</ItemTemplate>
<SeparatorTemplate>, </SeparatorTemplate>
<FooterTemplate> )
</FooterTemplate>
</asp:DataList>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:DataList>
<p>
<asp:DataList
EnableViewState="false" id="Fields"
runat="server" Gridlines=None BorderStyle="none" width="100%" BorderWidth=0>
<HeaderTemplate>
<table cellspacing=0
width="100%">
<tr><td
class="class_header"><b><font size=2> Fields
</font></b></td></tr>
<tr bgcolor="eeeeee">
<td width="120" ><b><u> Visibility
</td>
<td width="100"><b><u> Type </td>
<td ><b><u> Name </td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr bgcolor="eeeeee">
<td width="120">
<nobr><span InnerHTML=<%# ((SortTable)
Container.DataItem)["Access"]%> runat=server /></nobr>
</td>
<td width="100">
<asp:HyperLink text=<%# ((SortTable) Container.DataItem)["Type"]
%> NavigateUrl=<%# GetUrl(Container.DataItem) %> runat=server/>
</td> <td>
<span InnerHTML=<%# ((SortTable)
Container.DataItem)["Name"] %> runat=server />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:DataList>
<p>
<asp:DataList EnableViewState="false"
id="Events" runat="server" Gridlines=None
BorderStyle="none"
width="100%" BorderWidth=0>
<HeaderTemplate>
<table cellspacing=0
width="100%">
<tr><td
class="class_header"><b><font size=2> Events
</font></b></td></tr>
<tr bgcolor="eeeeee">
<td width="120" ><b><u> Multicast
</td>
<td width="100"><b><u> Type </td>
<td ><b><u> Name </td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr bgcolor="eeeeee">
<td width="120">
<nobr><span InnerHTML=<%# ((SortTable) Container.DataItem)["Access"]%>
runat=server /></nobr>
</td>
<td width="100">
<asp:HyperLink text=<%# ((SortTable)
Container.DataItem)["Type"] %> NavigateUrl=<%#
GetUrl(Container.DataItem) %> runat=server/>
</td>
<td>
<span InnerHTML=<%# ((SortTable) Container.DataItem)["Name"]
%> runat=server />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:DataList>
<p>
<asp:DataList
EnableViewState="false" id="Properties"
runat="server" Gridlines=None BorderStyle="none"
BorderWidth=0 width="100%">
<HeaderTemplate>
<table
cellspacing=0 width="100%" >
<tr><td
class="class_header"><b><font size=2> Properties
</font></b></td></tr>
<tr
bgcolor="eeeeee">
<td
width="75"><b><u>Visibility</td>
<td
width="100"><b><u>Type</td>
<td
width="150"><b><u>Name</td>
<td><b><u>Accessibility</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr
bgcolor="eeeeee">
<td
width="75"><span InnerHTML=<%# ((SortTable)
Container.DataItem)["Visibility"] %> runat=server />
</td>
<td
width="100">
<asp:HyperLink
runat=server runat="server" text=<%# ((SortTable) Container.DataItem)["Type"]
%> NavigateUrl=<%# GetUrl(Container.DataItem) %>/> </td>
<td
width="150"><span InnerHTML=<%# ((SortTable)
Container.DataItem)["Name"]%> runat=server/>
<asp:DataList
EnableViewState="false" runat=server RepeatLayout="Flow"
ShowFooter=true
RepeatDirection="Horizontal"
datasource=<%# ((SortTable) Container.DataItem)["Params"]
%>>
<ItemTemplate>
( <asp:HyperLink runat=server text=<%# ((SortTable)
Container.DataItem)["ParamType"]%> NavigateUrl=<%# GetUrl(Container.DataItem)
%> />
<span InnerHtml=<%# ((SortTable)
Container.DataItem)["ParamName"] %> runat=server /> )
</ItemTemplate>
</asp:DataList>
</td><td><span InnerHTML=<%# ((SortTable)
Container.DataItem)["Access"]%> runat=server/></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:DataList>
<p>
<asp:DataList EnableViewState="false"
id="Methods" runat="server" Gridlines=None
borderstyle="none" borderwidth="0"
width="100%">
<HeaderTemplate>
<table cellspacing=0
>
<tr><td
class="class_header"><b><font size=2> Methods
</font></b></td></tr>
<tr bgcolor="eeeeee">
<td width="75"
><b><u>Visibility</td>
<td width="100"><b><u>Return
</td>
<td width="100"><b><u>Name</td>
<td
width="600"><b><u>Parameters</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr bgcolor="eeeeee">
<td
width="75"><nobr><span runat=server
InnerHtml=<%# ((SortTable) Container.DataItem)["Access"]%>
/></nobr></td>
<td width="100">
<asp:HyperLink
runat=server NavigateUrl=<%# GetUrl(Container.DataItem) %> text=<%#
((SortTable) Container.DataItem)["Type"]%>/>
</td>
<td width="100"><span runat=server
InnerHtml=<%# ((SortTable)
Container.DataItem)["Name"]%>/></td>
<td
width="900">
<asp:DataList EnableViewState="false" runat=server
datasource=<%# ((SortTable) Container.DataItem)["Params"]
%>
RepeatLayout=Flow RepeatDirection="Horizontal"
showfooter=true >
<HeaderTemplate>
(
</HeaderTemplate>
<ItemTemplate>
<asp:HyperLink text=<%# ((SortTable)
Container.DataItem)["ParamType"].ToString() %> NavigateUrl=<%#
GetUrl(Container.DataItem) %> runat=server />
<span InnerHtml=<%# ((SortTable)
Container.DataItem)["ParamName"] %> runat=server />
</ItemTemplate>
<SeparatorTemplate> ,</SeparatorTemplate>
<FooterTemplate>
)
</FooterTemplate>
</asp:DataList>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:DataList>
<p>
<asp:DataList EnableViewState="false"
id="SuperClasses" style="margin-left:10"
runat="server" RepeatLayout="Flow"
RepeatDirection="horizontal" width="100%">
<HeaderTemplate>
<font
size=2><b> Hierarchy </b></font> <br>
</HeaderTemplate>
<ItemTemplate>
<asp:HyperLink runat=server NavigateUrl=<%#
GetUrl(Container.DataItem) %> text=<%# ((SortTable)
Container.DataItem)["FullName"]%> />
</ItemTemplate>
<SeparatorTemplate>
<font face="Verdana"
style="font-size:8pt"><nobr>---></nobr>
</SeparatorTemplate>
</asp:DataList>
<p>
<asp:DataList EnableViewState="false"
id="Interface1" runat=server style="margin-left:10"
RepeatDirection="horizontal"
RepeatLayout="Flow"
width="100%">
<HeaderTemplate>
<font
size=2><b> Implements </b></font> <br>
</HeaderTemplate>
<ItemTemplate>
<asp:HyperLink runat=server NavigateUrl=<%#
GetUrl(Container.DataItem) %> text=<%# ((SortTable)
Container.DataItem)["FullName"]%> />
</ItemTemplate>
<SeparatorTemplate>
<font face="Verdana"
style="font-size:8pt">,
</SeparatorTemplate>
</asp:DataList>
<p>
<asp:DataList EnableViewState="false"
id="SubClasses" style="margin-left:10" runat=server
RepeatLayout="Flow"
RepeatDirection="horizontal"
width="100%">
<HeaderTemplate>
<font size=2> <b>Subclassed By
</b></font> <br>
</HeaderTemplate>
<ItemTemplate>
<asp:HyperLink runat=server NavigateUrl=<%#
GetUrl(Container.DataItem) %> text=<%# ((SortTable)
Container.DataItem)["FullName"]%> />
</ItemTemplate>
<SeparatorTemplate>
<font
face="Verdana" style="font-size:8pt">,
</SeparatorTemplate>
</asp:DataList>
<p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
</body>
</html>
b.cs
using System ;
using System.Web;
using System.Web.UI;
using System.Collections;
using System.Reflection;
namespace ClassInfo {
public class SortTable : Hashtable, IComparable {
public String
sortField;
public SortTable()
: this(null) {
}
public
SortTable(String sField) {
sortField =
sField;
}
public int
CompareTo(Object b) {
if ( sortField
== null ) {
return 0;
}
return
((String)this[sortField]).CompareTo((String)((SortTable)b)[sortField]);
}
}
public class DisplayEvents : ArrayList {
public DisplayEvents(Type
classType) {
System.Reflection.EventInfo[] eventInfos = classType.GetEvents();
if (eventInfos ==
null)
return;
ArrayList eventTable =
new ArrayList();
for (int x=0;
x<eventInfos.Length; x++) {
SortTable
eventDetails = new SortTable("Name");
eventDetails["Assembly"] = eventInfos[x].EventHandlerType.Assembly.GetName().Name;
eventDetails["Name"] = eventInfos[x].Name;
eventDetails["Type"] = eventInfos[x].EventHandlerType.Name;
eventDetails["GetType"] = eventInfos[x].EventHandlerType.Name;
eventDetails["Namespace"] = eventInfos[x].EventHandlerType.Namespace;
if (eventInfos[x].IsMulticast == true) {
eventDetails["Access"] = "multicast ";
}
this.Add(eventDetails);
}
this.Sort();
}
}
public class DisplayFields : ArrayList
{
public DisplayFields(Type classType)
{
System.Reflection.FieldInfo[] fieldInfos = classType.GetFields();
if (fieldInfos == null)
return;
ArrayList fieldTable =
new ArrayList();
for (int x=0;
x<fieldInfos.Length; x++) {
SortTable
fieldDetails = new SortTable("Name");
fieldDetails["Assembly"] =
fieldInfos[x].GetType().Assembly.GetName().Name;
fieldDetails["Name"] = fieldInfos[x].Name;
fieldDetails["Type"] =
fieldInfos[x].FieldType.Name;
if((
fieldInfos[x].FieldType.IsArray && fieldInfos[x].FieldType.Name !=
"Array") ||
fieldInfos[x].FieldType.IsPointer)
{
fieldDetails["GetType"]
= fieldInfos[x].FieldType.GetElementType().Name;
fieldDetails["Namespace"] =
fieldInfos[x].FieldType.GetElementType().Namespace;
}
else {
fieldDetails["GetType"]
= fieldInfos[x].FieldType.Name;
fieldDetails["Namespace"]
= fieldInfos[x].FieldType.Namespace;
}
if
(fieldInfos[x].IsPublic == true){
fieldDetails["Access"] = "public ";
}
else if
(fieldInfos[x].IsPrivate == true){
fieldDetails["Access"]
= "private ";
}
else if
(fieldInfos[x].IsFamily == true){
fieldDetails["Access"] = "protected ";
}
if
(fieldInfos[x].IsStatic == true){
fieldDetails["Access"] = ((String)
fieldDetails["Access"]) + "static ";
}
if
(fieldInfos[x].IsLiteral == true){
fieldDetails["Access"] = ((String)
fieldDetails["Access"]) + "const ";
}
this.Add(fieldDetails);
}
this.Sort();
}
}
public class DisplayConstructors : ArrayList {
public
DisplayConstructors(Type classType) {
System.Reflection.ConstructorInfo[] constructorInfos =
classType.GetConstructors();
if
(constructorInfos == null)
return;
for (int x=0;
x<constructorInfos.Length; x++) {
SortTable
constructorDetails = new SortTable();
constructorDetails["Assembly"] =
constructorInfos[x].GetType().Assembly.GetName().Name;
constructorDetails["Name"] =
classType.Name;
if
(constructorInfos[x].IsPublic == true) {
constructorDetails["Access"] = "public ";
}
else if
(constructorInfos[x].IsPrivate == true) {
constructorDetails["Access"]
= "private ";
}
else if
(constructorInfos[x].IsFamily == true)
{
constructorDetails["Access"] = "protected ";
}
System.Reflection.ParameterInfo[] paramInfos = constructorInfos[x].GetParameters();
if (paramInfos !=
null) {
ArrayList
paramTable = new ArrayList();
for (int y=0;
y<paramInfos.Length; y++) {
SortTable paramDetails = new SortTable();
paramDetails["Assembly"]
= paramInfos[y].GetType().Assembly.GetName().Name;
paramDetails["ParamName"] = paramInfos[y].Name;
paramDetails["ParamType"] = paramInfos[y].ParameterType.Name;
if ( (
paramInfos[y].ParameterType.IsArray && paramInfos[y].ParameterType.Name
!="Array" ) || paramInfos[y].ParameterType.IsPointer ) {
paramDetails["GetType"]
= paramInfos[y].ParameterType.GetElementType().Name ;
paramDetails["Namespace"] =
paramInfos[y].ParameterType.GetElementType().Namespace ;
}
else {
paramDetails["GetType"]
= paramInfos[y].ParameterType.Name;
paramDetails["Namespace"] =
paramInfos[y].ParameterType.Namespace ;
}
paramTable.Add(paramDetails);
}
constructorDetails["Params"] = paramTable;
}
this.Add(constructorDetails);
}
}
}
public class DisplayProperties : ArrayList {
public DisplayProperties(Type classType) {
System.Reflection.PropertyInfo[] propertyInfos =
classType.GetProperties();
if (propertyInfos
== null)
return;
ArrayList
propertyTable = new ArrayList();
for (int x=0;
x<propertyInfos.Length; x++) {
SortTable
propertyDetails = new SortTable("Name");
if(propertyInfos[x].GetGetMethod() != null) {
if((
propertyInfos[x].GetGetMethod().ReturnType.IsArray &&
propertyInfos[x].GetGetMethod().ReturnType.Name !="Array" ) ||
propertyInfos[x].GetGetMethod().ReturnType.IsPointer ) {
propertyDetails["GetType"]
= propertyInfos[x].GetGetMethod().ReturnType.GetElementType().Name;
propertyDetails["Namespace"] =
propertyInfos[x].GetGetMethod().ReturnType.GetElementType().Namespace;
} else {
propertyDetails["GetType"]
= propertyInfos[x].GetGetMethod().ReturnType.Name;
propertyDetails["Namespace"] =
propertyInfos[x].GetGetMethod().ReturnType.Namespace;
}
propertyDetails["Type"]
= propertyInfos[x].GetGetMethod().ReturnType.Name;
propertyDetails["Assembly"]
= propertyInfos[x].GetGetMethod().ReturnType.Assembly.GetName().Name;
propertyDetails["Name"]
= propertyInfos[x].Name;
if (propertyInfos[x].GetGetMethod().IsPublic
== true) {
propertyDetails["Visibility"] = "public";
} else if
(propertyInfos[x].GetGetMethod().IsPrivate == true) {
propertyDetails["Visibility"] = "private";
} else if
(propertyInfos[x].GetGetMethod().IsFamily == true) {
propertyDetails["Visibility"] = "protected";
}
if
(propertyInfos[x].GetGetMethod().IsStatic == true) {
propertyDetails["Visibility"] = ((String) propertyDetails["Visibility"]) +
" static";
}
if
(propertyInfos[x].GetSetMethod() == null) {
propertyDetails["Access"] =
"[Get]" ;
} else {
propertyDetails["Access"] = "[Get , Set]" ;
}
System.Reflection.ParameterInfo[]
paramInfos = propertyInfos[x].GetGetMethod().GetParameters();
if (paramInfos !=
null) {
ArrayList
paramTable = new ArrayList();
for (int y=0;
y<paramInfos.Length; y++) {
SortTable
paramDetails = new SortTable();
paramDetails["Assembly"] =
paramInfos[y].GetType().Assembly.GetName().Name;
paramDetails["ParamName"] = paramInfos[y].Name;
paramDetails["ParamType"] = paramInfos[y].ParameterType.Name;
if ((
paramInfos[y].ParameterType.IsArray && paramInfos[y].ParameterType.Name
!="Array") ||paramInfos[y].ParameterType.IsPointer ) {
paramDetails["GetType"] = paramInfos[y].ParameterType.GetElementType().Name ;
paramDetails["Namespace"] =
paramInfos[y].ParameterType.GetElementType().Namespace ;
} else {
paramDetails["GetType"]
= paramInfos[y].ParameterType.Name;
paramDetails["Namespace"] =
paramInfos[y].ParameterType.Namespace ;
}
paramTable.Add(paramDetails);
}
propertyDetails["Params"] = paramTable;
}
} else if(propertyInfos[x].GetSetMethod() != null) {
propertyDetails["GetType"] = propertyInfos[x].GetSetMethod().ReturnType.Name;
propertyDetails["Namespace"] =
propertyInfos[x].GetSetMethod().ReturnType.Namespace;
propertyDetails["Type"]
= propertyInfos[x].GetSetMethod().ReturnType.Name;
propertyDetails["Assembly"]
= propertyInfos[x].GetGetMethod().ReturnType.Assembly.GetName().Name;
propertyDetails["Name"]
= propertyInfos[x].Name;
if (propertyInfos[x].GetSetMethod().IsPublic == true) {
propertyDetails["Visibility"] = "public";
} else if
(propertyInfos[x].GetSetMethod().IsPrivate == true) {
propertyDetails["Visibility"] = "private";
} else if
(propertyInfos[x].GetSetMethod().IsFamily == true) {
propertyDetails["Visibility"] = "protected";
}
if (propertyInfos[x].GetSetMethod().IsStatic == true) {
propertyDetails["Visibility"] = ((String)
propertyDetails["Visibility"]) + " static";
}
propertyDetails["Access"] = "[ Set ]" ;
System.Reflection.ParameterInfo[] paramInfos =
propertyInfos[x].GetSetMethod().GetParameters();
if (paramInfos != null) {
ArrayList
paramTable = new ArrayList();
for
(int y=0; y<paramInfos.Length; y++) {
SortTable
paramDetails = new SortTable();
paramDetails["Assembly"] =
paramInfos[y].GetType().Assembly.GetName().Name;
paramDetails["ParamName"] = paramInfos[y].Name;
paramDetails["ParamType"] = paramInfos[y].ParameterType.Name;
if(( paramInfos[y].ParameterType.IsArray &&
paramInfos[y].ParameterType.Name !="Array") ||
paramInfos[y].ParameterType.IsPointer) {
paramDetails["GetType"]
= paramInfos[y].ParameterType.GetElementType().Name ;
paramDetails["Namespace"] =
paramInfos[y].ParameterType.GetElementType().Namespace ;
}
else {
paramDetails["GetType"]
= paramInfos[y].ParameterType.Name;
paramDetails["Namespace"] =
paramInfos[y].ParameterType.Namespace ;
}
paramTable.Add(paramDetails);
}
propertyDetails["Params"]
= paramTable;
}
}
this.Add(propertyDetails);
}
this.Sort();
}
}
public class
DisplayMethods : ArrayList {
public
DisplayMethods(Type classType, String myclassname) {
System.Reflection.MethodInfo[] methodInfos = classType.GetMethods() ;
if
(methodInfos == null)
return;
for (int x=0;
x<methodInfos.Length; x++) {
if((String.Compare(myclassname,methodInfos[x].DeclaringType.Name
)==0)&&(methodInfos[x].IsPublic || methodInfos[x].IsFamily) &&
(!(methodInfos[x].IsSpecialName)) ) {
SortTable
MethodDetails = new SortTable("Name");
MethodDetails["Assembly"]
= methodInfos[x].GetType().Assembly.GetName().Name;
MethodDetails["Name"] = methodInfos[x].Name;
MethodDetails["Type"] = methodInfos[x].ReturnType.Name;
if(( methodInfos[x].ReturnType.IsArray &&
methodInfos[x].ReturnType.Name !="Array") || methodInfos[x].ReturnType.IsPointer) {
Type ReturnElementType =
methodInfos[x].ReturnType.GetElementType();
while(ReturnElementType.IsArray) {
ReturnElementType
= ReturnElementType.GetElementType();
}
MethodDetails["GetType"] = ReturnElementType.Name ;
MethodDetails["Namespace"] =
ReturnElementType.Namespace ;
} else {
MethodDetails["GetType"] =
methodInfos[x].ReturnType.Name;
MethodDetails["Namespace"] =
methodInfos[x].ReturnType.Namespace ;
}
if (methodInfos[x].IsPublic == true) {
MethodDetails["Access"] = "public ";
} else if (methodInfos[x].IsPrivate == true) {
MethodDetails["Access"] = "private ";
} else if (methodInfos[x].IsFamily == true) {
MethodDetails["Access"] = "protected ";
}
if (methodInfos[x].IsStatic == true) {
MethodDetails["Access"] = ((String)
MethodDetails["Access"]) + "static ";
}
System.Reflection.ParameterInfo[] paramInfos =
methodInfos[x].GetParameters();
if (paramInfos != null) {
ArrayList paramTable = new ArrayList();
for (int y=0; y<paramInfos.Length; y++) {
SortTable paramDetails =
new SortTable();
paramDetails["Assembly"]
= paramInfos[y].GetType().Assembly.GetName().Name;
paramDetails["ParamName"] = paramInfos[y].Name;
paramDetails["ParamType"]
= paramInfos[y].ParameterType.Name;
if(( paramInfos[y].ParameterType.IsArray &&
paramInfos[y].ParameterType.Name != "Array" ) || paramInfos[y].ParameterType.IsPointer) {
paramDetails["GetType"]
= paramInfos[y].ParameterType.GetElementType().Name ;
paramDetails["Namespace"] =
paramInfos[y].ParameterType.GetElementType().Namespace ;
} else {
paramDetails["GetType"]
= paramInfos[y].ParameterType.Name;
paramDetails["Namespace"] = paramInfos[y].ParameterType.Namespace
;
}
paramTable.Add(paramDetails);
}
MethodDetails["Params"] = paramTable;
}
this.Add(MethodDetails);
}
}
this.Sort();
}
}
public class DisplayInterfaces : ArrayList {
public
DisplayInterfaces(Type classType) {
Type[]
classInterfaces = classType.GetInterfaces();
for(int x = 0
; x < classInterfaces.Length ; x++) {
SortTable
interfaceDetails = new SortTable();
interfaceDetails["Assembly"] = classInterfaces[x].Assembly.GetName().Name;
interfaceDetails["FullName"] = classInterfaces[x].FullName;
interfaceDetails["GetType"] = classInterfaces[x].Name;
interfaceDetails["Namespace"] = classInterfaces[x].Namespace;
this.Add(interfaceDetails);
}
}
}
public class
DisplaySuperclasses : ArrayList {
public
DisplaySuperclasses(Type classType) {
Type SuperClass
;
SortTable
classDetails = new SortTable();
classDetails["Assembly"]
= classType.Assembly.GetName().Name;
classDetails["FullName"]
= classType.FullName;
classDetails["GetType"]
= classType.Name;
classDetails["Namespace"]
= classType.Namespace;
this.Add(classDetails);
while
(classType.BaseType != null) {
SortTable
superclassDetails = new SortTable();
SuperClass
= classType.BaseType ;
classType = SuperClass
;
superclassDetails["Assembly"] = SuperClass.Assembly.GetName().Name;
superclassDetails["FullName"] = SuperClass.FullName;
superclassDetails["GetType"] = SuperClass.Name;
superclassDetails["Namespace"] = SuperClass.Namespace;
this.Add(superclassDetails) ;
}
this.Reverse()
;
}
}
public class
DisplaySubClasses : ArrayList {
private Type classType ;
private
Module[] CorRuntime ;
private
Type[] CorClasses;
private
String myclassname ;
private
Type[] classInterfaces;
public
DisplaySubClasses(Type classtype, ArrayList ModuleName) {
this.classType = classtype;
myclassname =
classType.FullName ;
if
(classType.IsInterface ) {
for(int y = 0 ; y <
ModuleName.Count ;y++) {
CorRuntime =
Assembly.Load(ModuleName[y].ToString()).GetModules();
CorClasses = CorRuntime[0].GetTypes() ;
for(int x= 0 ; x <
CorClasses.Length; x++) {
classType =
CorClasses[x];
classInterfaces
= classType.GetInterfaces() ;
for(int i = 0 ; i < classInterfaces.Length ; i++)
{
if(String.Compare(myclassname , classInterfaces[i].FullName )==0) {
SortTable subclassDetails
= new SortTable("FullName");
subclassDetails["Assembly"] = classType.Assembly.GetName().Name;
subclassDetails["FullName"] = classType.FullName;
subclassDetails["GetType"] = classType.Name;
subclassDetails["Namespace"] = classType.Namespace;
this.Add(subclassDetails) ;
}
}
}
}
} else {
for(int y = 0; y < ModuleName.Count ; y++) {
CorRuntime = Assembly.Load(ModuleName[y].ToString()).GetModules();
CorClasses =
CorRuntime[0].GetTypes();
for( int x= 0 ; x< CorClasses.Length ;x++) {
classType = CorClasses[x].BaseType ;
if ( null != classType )
{
if( String.Compare(classType.FullName, myclassname)==0) {
SortTable subclassDetails = new SortTable("FullName");
subclassDetails["Assembly"] = CorClasses[x].Assembly.GetName().Name;
subclassDetails["FullName"] = CorClasses[x].FullName;
subclassDetails["GetType"] = CorClasses[x].Name;
subclassDetails["Namespace"] = CorClasses[x].Namespace;
this.Add(subclassDetails) ;
}
}
}
}
}
this.Sort();
}
}
}
In the web.config file, there are
far more assemblies than is desirable, to carry out a search for the names of
namespaces. In the a.aspx, we have not introduced too many structural changes.
The code is voluminous, but most of it has been explained earlier. Hence, we
shall make a quick run through.
In the Page_Load function, where
life originates for our aspx application, we first display the namespaces,
depending upon the existence of a parameter called class in the Url.
• If the class parameter is available,
all the details of that class are displayed, using the function DisplayClass.
• If it is not present, a set of
classes from the namespace, are displayed using the function DisplayClassList.
The DisplayClassList function
remains the same as before. Modifications have been incorporated in the
DisplayClass function. Where we had created one object earlier, which was an
instance of DisplayMethods, we now have created seven objects. All these
classes reside in the file b.cs. We therefore, have seven occurrences of the
'if' statement. They initialize seven DataList objects DataSource members by
these ArrayList types, when the Count property is greater than zero. In their
order of appearance, we have ArrayList objects that store details of the
following:
• Sub-classes
• Constructors
• Fields
• Methods
• Superclasses
• Interfaces
We start with a DataList named
Namespace1 that displays the list of Namespaces in the first column. Then, we
have a div spnClassName that either displays the interface name or the class
name. As mentioned earlier, the table, td and tr tags are utilized for display
purposes.
The DataList Classes store the
class names, while the DataList Interfaces store the names of the Interfaces
belonging to a Namespace. To display the list of constructors, we use a
DataList called Constructors. In the template named headertemplate for
constructors, we simply display the headings' Visibility and Parameters in a
tabular format. In the class DisplayConstructors, indexers with names like
Access and Name, are created and used in the itemtemplate.
There is always a likelihood of a
complication stirring in situations, where the number can vary. Here, the
number of parameters passed to the constructor, varies. Hence, we need a
DataList within a DataList. The inner DataList is not assigned any name, but
its DataSource member is initialized to the indexer variable called Params.
Params is an ArrayList with members having the name of ParamType, etc. This is
exactly what we had done earlier, in the case of methods. There is no
alteration in the basic ground rules.
The mechanism employed to display
different items, is as follows:
• To display the fields, a DataList
called Fields is put into action.
• To display properties, a DataList
called Properties is used.
• Superclasses are retrieved by a
DataList called SuperClasses.
• Interfaces are retrieved by a
DataList called Interface1.
• Sub-classes need their own DataList
called SubClasses.
It is definitely not our concern,
as to how the code that figured out the sub-classes, was written. We are not
going to get distracted by the C# code written by someone else. We shall
primarily focus on the presentation logic in the aspx file. The central idea of
a class browser is that, some C# code is responsible for creating an ArrayList.
Thereafter, the DataList in the aspx file displays it in a presentable form.
The main chunk of the source code
lies in the classes present in the file b.cs. We have already seen as to how
methods are to be retrieved. The rest of the code is quite similar. Let us
commence with the mechanism for retrieving the constructors that are present in
a specific type.
The class that retrieves fields
is called DisplayFields. It is derived from ArrayList. The GetFields function
is used to return an array of FieldInfo objects. The code to fill up the
ArrayList object remains the same as that used for methods. The class named
DispalyConstructors uses the function GetConstructors to generate a list of
ConstructorInfo objects. Similarly, the class called DisplayProperties uses the
function GetPropeties to return a PropertyInfo array. Here, one more function
named GetSetMethod is added, which returns a null value, if the property accessor
has only a get accessor. The class DisplayInterfaces is similar to the method
class.
We need to be acquainted with the
class hierarchy, which consists of the list of all the classes that a specific
class is derived from, and also, all the classes that derive from it. The class
DisplaySuperclasses meets the requirement, but uses a very original approach.
We create an object SuperClass,
derived from Type and a Hashtable object classDetails. We initialize three
indexer variables named FullName, GetType and Namespace, to the properties
FullName, Name and Namespace, which are present in the class Type,
respectively. Then, we append this data to the ArrayList class.
A Type has a property called
dBaseType, which is set to null, whenever the Type has no base Type. Putting it
differently, only the Objects type will have the BaseType property set to null,
since all types are finally derived from the class Object. The while loop will
repeat itself for the number of types that we have derived from.
For each type, a Hashtable called
superclassDetails is created and the SuperClass Type object is initialized to
the BaseType. This value is also stored in the parameter variable named
ClassType, because we shall lose the earlier value of SuperClass, in the next
iteration of the while loop. Once again, the FullName, GetType and Namespace
indexer variables are initialized, and thereafter, the new Hashtable object is
added to the ArrayList.
The while loop stores data in the ArrayList in the reverse order. We intend to display the class Object first, leading upto the class whose details we are interested in. Thus, we need to reverse the order of the data in the ArrayList.