Q: Enumerate Static Fields of an non-instantiated class?!?

  • Thread starter Thread starter Sky
  • Start date Start date
S

Sky

Hi: need a little help with Reflection on Static fields, from within Static
Methods:



If I define a class:

class Customers{
public int ID;
public string FirstName;
public string LastName;
}

and I want to get an array of these FieldNames WITHOUT INSTANTIATING THE
CLASS ... (to make SQL from, on the fly)... how do I do this?




Situation II, in case I go a little further...(and don't get lost!) what
about something like:


class XFieldInfo {
public string FieldName ="";
public System.Type FieldType;
public int FieldLength;
}

class Schema_Customer{
public static ID = new XFieldInfo("ID",System.Int32, 8);
public static String FN_NAMEFIRST = new XFieldInfo
("FirstName",System.String, 32);
public static String FN_NAMELAST = new XFieldInfo
("LastName",System.String, 32);
}

How would I iterate the above to get an array that contains "FirstName", and
"LastName"?
I tried something like (but it didn't work):

public static string[] Fields(){
System.Collections.ArrayList oResult = new
System.Collections.ArrayList();

//It's this line that I think that is hanging me up
System.Type tType =
Test.GetType();//System.Type.GetType("Shema_Customers");
//but this doesn't work either in a static function:
System.Type tType = this.GetType();

System.Reflection.FieldInfo[] tFieldInfos =
tType.GetFields(System.Reflection.BindingFlags.Static);
foreach (System.Reflection.FieldInfo tFieldInfo in tFieldInfos) {
if (tFieldInfo.Name.ToUpper().Substring(0,3) == "FN_") {
oResult.Add(tFieldInfo.GetValue(null));
}
}
return (string[])oResult.ToArray(System.Type.GetType("System.String"));
}


I'm driving myself nuts with trying to get a grip on replacing my SQL calls
with some form of DataObjects...and some of the tricks I used to do by
making SQL on the fly based on info gleamed from schema queries...are
difficult to bring across...

Any and all help greatly appreciated
;-)
 
Sky said:
System.Reflection.FieldInfo[] tFieldInfos =
tType.GetFields(System.Reflection.BindingFlags.Static);

Most likely the problem is this line. BindingFlags always requires at least
two parts: instance/static and public/nonpublic.

FieldInfo[] tFieldInfos = typeof( Schema_Customer).GetFields(
BindingFlags.Static | BindingFlags.Public );

Should do the trick, even in a static method (but, possibly not a static ctor,
because you can't count on your static ctor being called before another
type's static ctor).


Derek Harmon
 
Dear Derek:
I tried your suggestion, no cigar.
What I see the problem is my inability to get the Type info from a
non-instantiated class object... I've commented the lines that are holding
me up -- I think:

<%@ Page Language="C#" %>
<%@ Import namespace="System" %>

<script language="C#" runat="server">
//namespace NA { //Interesting: it won't accept a namespace being
defined on this single page test?
class cTest{

static string FN_A = "Wow1";
static string FN_B = "Wow2";


public static string[] Fields(){
System.Collections.ArrayList oResult = new
System.Collections.ArrayList();

//****************************************************
//For some reason, in an solo ASPX page, I was not able to define a
namespace.
//The following "cTest" is obviously not enough to find it -- this
returns NULL...
//What Namespace, if any, is implied here????
//System.Type tType = System.Type.GetType("cTest");
//Can't do this either, as we are in a static function, and on top of
that, probably not instantiated:
//How else can I get the type of this non-instantiated class????
//System.Type tType = this.GetType();
//****************************************************
System.Reflection.FieldInfo[] tFieldInfos =
tType.GetFields(System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.Public );
foreach (System.Reflection.FieldInfo tFieldInfo in tFieldInfos) {
if (tFieldInfo.Name.ToUpper().Substring(0,3) == "FN_") {
oResult.Add(tFieldInfo.GetValue(null));
}
}
return (string[])oResult.ToArray(System.Type.GetType("System.String"));
}

}//Class:End
//}//Namespace:End
</script>

<%
//****************************************************
//Let's see what happens:
Response.Write("Type:"+ System.Type.GetType("Test"));
//Response.Write("Number of Fields found:" + Test.Fields().Length);

//****************************************************
%>
 
Sky said:
<%@ Page Language="C#" %>
<%@ Import namespace="System" %> : :
//namespace NA { //Interesting: it won't accept a namespace being
defined on this single page test?

This is because ASP.NET compiles this ASPX page into a class, and has already
placed everything into the ASP namespace. If you go snooping around under the

%WINDIR%\Microsoft.NET\Framework\v1.0.3705\Temporary ASP.NET Files\
(or replace v1.0.3705 with v1.1.4322 if you're using the 1.1 version of the Framework)

folder, you should see some of the source code generated during ASP.NET's behind-
the-scenes compilation of your one-page ASPX projects.

:
//What Namespace, if any, is implied here????
//System.Type tType = System.Type.GetType("cTest");

I believe it will search the calling assembly (generated by ASP.NET for this
Page) and then search mscorlib, when a fully-qualified type name is not given.

: :
Response.Write("Type:"+ System.Type.GetType("Test"));

The type name is cTest, so Test should find nothing.

A benefit of typeof( ) over using the string-parameterized versions of similar
functions, is that the C# compiler will tell you at compile-time if it cannot see
the type definition. :-)

I'm going to take a stab in the dark and suggest looking for a type named:
"ASP.WebForm1_aspx+cTest", on the hypothesis cTest may have been
nested and your ASPX file name is ''WebForm1.aspx''.

You might also try running ILDASM on the assembly generated for your one
page ASPX in the web application's bin folder, and see how the classes were
arranged.


Derek Harmon
 
Derek:

Your tip for using typeof() instead of System.Type.GetType("..."); was a
fantastic boon -- already found several bugs due to typing errors
=;-o

And of course it solves the problem list below as well since we are talking
directly to the class object within the same scope -- no need to get lost in
quotation marks...no need to care what the page is doing in the back end (or
atleast...not this weekend...)


There are small things, that if you don't get can about C# and the
framework, drive you nuts.
Last month I found out that char's are wrapped in single quotes instead of
double. It's dumb....But when you don't know that, you spend oodles of
wasted time making useless junk function calls like

s.split(",".ToCharArray());

which is not only verbose, but leads to errors if the divchar is more than
one char long...

All to say that I really really really appreciate these little 'nudges' in
the right direction. Thanks!!!
 
Dear Derek -- again thanks. Solved the question.

The namespace was easily found by doing:
typeof(cTest).Namespace... and it was simply ASP as you suggested. Nice to
know for future.

And of course, since today is a day to explore and get things down in C#,
launched right into another area, which you may or may not have seen the
thread of... but it's all tied together:


What I just wrote to list the classes within a namespace, and it works (bare
typos... ;-),
is listed below...I just havn't figured out a way to pass a Namespace as an
argument...
(BTW: What is a namespace -- is there a System.Type for it? Couldn't see
one)...

public string[] EnumerateClassesInNameSpace(System.Type
qAClassWithinNamespace){

System.Collections.ArrayList tResult = new System.Collections.ArrayList();

System.Type tTypeIN = qClassWithinNamespace;

System.Type tType;

string tNS = tTypeIN.Namespace;

System.Type[] tTypes = tTypeIN.Assembly.GetTypes();

for (int i=0;i<tTypes.Length;i++){

tType = tTypes;

if ( (tType.MemberType == System.Reflection.MemberTypes.TypeInfo) &&

(tType.Namespace == tNS) ){

tResult.Add(tType);

}

}

return (System.String)tResult.ToArray(typeof(System.String));

}


I have to admit that I am a bit jittery on what exactly a TypeInfo defines.
From the list here on screen, It appears to be alist of classes. ...but then
why not have called it ClassInfo? Ie...I suspect that there is more to the
story than I can see..any knowledge on your end as to this?

Thanks!!!
 
Back
Top