First of all, According to C# documentation, any type allocates its static members once per Type rather than once per Open Type. Now lets define this using the code below :
public class MyType<T> where T : class { public static int Counter; static MyType() { Counter = 0; } public MyType() { Counter++; } }
Here this is actually a Generic Type that keeps track of the count of objects that per type creates. The Type instance here MyType<T> is called Open Type and can take form of any Type. Now lets create object of MyType.
MyType<string> ss = new MyType<string>(); ss = new MyType<string>(); ss = new MyType<string>(); MyType<object> oo = new MyType<object>(); oo = new MyType<object>(); oo = new MyType<object>(); Console.WriteLine(MyType<string>.Counter); Console.ReadKey(true);
Now we create 3 instance of string and 3 of Object. Thus the Console.WriteLine should show 6, right? .... Wrong.. Actually we here create two types using Generic Type MyType, one is MyType<string> and another is MyType<object>. So here MyType generates its own closed type and each of the type creates its Type interface when first instance of the object is called for, or rather when the Static constructor is called.
Thus if I call MyType<X>.Counter it will show 0 and will create a new Type and call the Static constructor immediately.
Now this is very easy here to call static members of a Generic type, but what if we want to call Static member of the Type we pass into as Generic Argument. Lets see...
public class MyType { public static void Try2CalMe() { Console.WriteLine("Wow. You finally called me!"); } public void CallMe() { Console.WriteLine("Called CallMe"); } }
Lets say I have a class defined with one static method and one instance method. As I have already told you that Generic Static members create its memory when it creates it first object, the same is true for non generic types. Hence when an instance of MyType is passed within a Generic Type as Type argument, you would already have the memory allocated for the Type. Now let us consider using this Type for our Generic Class.
public class MyGenericClass<T> { T MyTObject { get; set; } public void InstanceMethod() { if (this.MyTObject != null) this.MyTObject.CallMe(); } }
Well the line which calls CallMe leads to a problem, because the Generic Type does not have any idea about what Type it is going to take. Say for instance if I pass int variable as T it will take that also. Well to fix this problem we can put a constraint to Type T with a Where clause. But that doesnt solve our problem either. Even though we can call CallMe we cannot call Try2CallMe. There are few approaches that you can take to solve this problem.
- Working with your friend Reflection :
Reflection API can call any method from a Type. You can check whether the static Method is there in the type that is passed during Runtime and if exists you can call it. Lets try to call the method using Reflection :public class MyGenericClass<T> where T : MyType { public T MyTObject { get; set; } public void InstanceMethod() { if (this.MyTObject != null) { this.MyTObject.CallMe(); //Calling static member using Reflection Type currentType = typeof(T); var method = currentType.GetMethod("Try2CalMe", BindingFlags.Static | BindingFlags.Public); if(method != null) // Method exists method.Invoke(null, null); //We pass null as object for static member } } }
So here we first pass MyType as constraint (even though it makes the type strict to inherited members of MyType) and calling the member using Reflection. Yes, it can call it absolutely. - Putting it in intermediate Abstract base class:
Another option, or probably better approach is to create an intermediate abstract base class for all your types and call it. It is another option for you and probably a better one but remember, all of your members share the same static member here.public abstract class MyAType { public static void Try2CalMe() { Console.WriteLine("Wow. You finally called me!"); } public virtual void CallMe() { Console.WriteLine("Called CallMe"); } } public class MyGenericClass<T> where T : MyAType { public T MyTObject { get; set; } public void InstanceMethod() { if (this.MyTObject != null) { this.MyTObject.CallMe(); //Calling static member Directly here MyAType.Try2CalMe(); } } }
Here we create an abstract base class for MyType and we pass it as generic constraint. So any class that inherits from this base class can go as a Type for the class MyGenericClass and which in turn can call its static member directly.
There might be some other option available and known to you. I would like you to share that with me.
I hope you like this post.
Thanks.
No comments:
Post a Comment
Please make sure that the question you ask is somehow related to the post you choose. Otherwise you post your general question in Forum section.