tags:

views:

111

answers:

3

Suppose I have two classes that both contain a static variable, XmlTag. The second class inherits from the first class. I have a template method that needs to obtain the XmlTag depending on the which type it is using. What would be the best way to accomplish this, without having to create an instance of the type? Here is an example(that won't compile), that should hopefully illustrate what I'm talking about.

class A{
public static readonly string XmlTag = "AClass";
}

class B : A {
public static readonly string XmlTag = "BClass";
}

This method is currently invalid.. Static variables can't be accessed from Type paramaters apparently.

string GetName<T>(T AClass) where T : A
{
    return T.XmlTag;
}
+1  A: 

There's no direct way you could do that without resorting to reflection.

If you really want to do that (I encourage you to consider changing your high level design first):

To get a field value:

var returnValue = typeof(T).GetField("FieldName").GetValue(null);

To get a property:

var returnValue = typeof(T).GetProperty("PropertyName").GetValue(null, null);

To invoke a method:

typeof(T).InvokeMember("MethodName", BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic, null, null, null);
Mehrdad Afshari
+5  A: 

First off, stop thinking of generic methods as templates. They are NOT templates. They have very different behaviour from templates; your expectation that they behave like templates is possibly what is leading you astray in this situation.

Here is a series of articles I wrote about your scenario and why it is illegal.

http://blogs.msdn.com/ericlippert/archive/2007/06/14/calling-static-methods-on-type-variables-is-illegal-part-one.aspx

http://blogs.msdn.com/ericlippert/archive/2007/06/18/calling-static-methods-on-type-variables-is-illegal-part-two.aspx

http://blogs.msdn.com/ericlippert/archive/2007/06/21/calling-static-methods-on-type-variables-is-illegal-part-three.aspx

Note that of course the "dynamic" feature that I hint at in part three is in fact shipping with C# 4.0.

To address your actual question: "what's the best way to do this?" Presumably you have some problem which you believe a mechanism like this would solve. This mechanism doesn't actually exist in C#. It is impossible for us to deduce what problem you are actually trying to solve from the fact that you would like this mechanism to exist. Instead of asking "how can I make this impossible thing work in C#?" instead describe the real problem you have, and we can take a crack at trying to come up with an existing C# mechanism that better solves your real problem.

Eric Lippert
Thank you for your reply. Your articles were an interesting read. My problem is fairly simple but I'm having a difficult time thinking of a good solution: I have several child classes that each have their own unique xml-tag constant. I have a generic method, Load(), in another class that accepts any of these child classes and will load instance(s) of that class from an XmlNode. Load() needs to obtain the xml-tag based on the type it is using so it knows which xml tags to look for.
Silv3rSurf
The child classes will only be instantiated AFTER their xml-tag has been found.
Silv3rSurf
How many types are we talking about here? Two? three? hundreds? Or a potentially unbounded number?
Eric Lippert
A: 

Why don't you give the bas class a virtual GetTagName class, and have the inheriting classes override that one?

class A{
public virtual string GetXmlTagName()
  {
   return "AClass";
  }
}

it would solve your immediate symptom but Im not sure about solving your problem. It has a destinct code smell but without knowing more I might be wrong when I state that the notion of XML should exist in a differrent class and that having that in A and B is violating single responsibility principle. Basically I would know from the information Im just affraid of it

Rune FS
Yes, that would work, but I need to obtain the constant before instantiating the class.
Silv3rSurf
Then the posted method, GetName<T> wouldn't work. The method you've posted takes an argument of T (where T : A) so inside that method you'll always have an object (unless you pass null as the argument)
Rune FS