Click here to Skip to main content
15,881,561 members
Please Sign up or sign in to vote.
4.00/5 (2 votes)
the problem is that we cannot GetValue of a field (non generic) that only resides in base class that has generic type.
please see the code snippet below. calling
C#
f.GetValue(a)
will throw the exception with message: Late bound operations cannot be performed on fields with types for which Type.ContainsGenericParameters is true.

C#
class Program
 {
     static void Main(string[] args)
     {
         Type abstractGenericType = typeof (ClassB<>);
         FieldInfo[] fieldInfos =
             abstractGenericType.GetFields(BindingFlags.Public |  BindingFlags.Instance);

         ClassA a = new ClassA("hello");
         foreach(FieldInfo f in fieldInfos)
         {
             f.GetValue(a);// throws InvalidOperationhException
         }
     }
 }

 internal class ClassB<T>
 {
     public string str;
     public ClassB(string s)
     {
         str = s;
     }
 }

 internal class ClassA : ClassB<String>
 {
     public ClassA(string value) : base(value)
     {}
 }


Our design requires that we obtain FieldInfo first before we have any instances of actual objects. so we cannot use

C#
Type typeA = abstractGenericType.MakeGenericType(typeof(string));
FieldInfo[] fieldInfos = typeA.GetFields();

Thank you
Posted
Comments
Sergey Alexandrovich Kryukov 11-Jul-12 20:06pm    
Last "we cannot use" part is not clear. In the last code sample, there is no instantiation of any "actual objects". (I understand that you might require to avoid instantiating them.) Maybe you mean instantiation of a type out of a generic type. (If this is the case, I wouldn't understand why avoiding it.)
--SA

Ah, finally I got it. Maybe an interesting problem, but not making much sense.

Here is the thing: you are facing some limitation which is not 100% logically required. Your code sample looks convincing (not many people will really understand your explanation of it, it just so happens that I am busy with related things right now :-)). Who knows why such limitation was applied? Maybe only people who made this decision.

Nevertheless, this limitation makes perfect practical sense. I would speculate in this way: those Microsoft people just decided: "we don't want to deal with pathological cases which hardly can make a lot of practical sense anyway". Do you understand what pathological sense I mean? Look at your ClassB. This is a generic type where the generic parameter is not used. And this case is pathological in some sense, which I will try to explain later.

First, imagine that you omitted the generic parameter. It is quite obvious that your GetValue works in this case. It the generic parameter is never used, you could remove it painlessly. Theoretically, I could imagine that the system would treat such "pathological" type as equivalent to the terminal (instantiated) type without generic parameters. However, it would make the system more complex and harder to understand. All irregularities "for special cases" are usually bad. Throwing the exception you observe is always better and more understandable.

Now, from the other hand, imagine that the generic parameter is actually used. If it was used in the fields from your fieldInfos, it is absolutely apparent that your code would not make any sense, whatsoever. Really, the return result of GetValue has the compile-time type System.Object, but it should have some run-time type, which is supposed to be of the type T which… does not exist, because your metadata is obtained from the incomplete (generic) type ClassB.

I don't even think that using GetValue could be theoretically possible even if all the fields of fieldInfos were non-generic. (It is possible because you only take public members, according to your BindingFlags, so only some non-public members could be generic.) It's harder to see, but my idea is this: the key fact is that ClassB is not the type, so it does not have certain memory layout. The size of the generic parameter is unknown, so it could be infeasible to implement GetValue, because the memory offsets of even non-generic type are unknown. It needs getting into further detail, but at least it looks like a real obstacle to me.

The key problem here is that you are using a metadata from a generic type with the instance of a real (fully instantiated, non-generic) type. Those two type are unrelated: ClassA is assignment compatible with ClassB<string> but not with ClassB<>, which cannot have instances at all. A generic type is not a type at all. (The term "generic type" suggest it is, as it suggests a statement "a generic type is a type", which is not true; no wonder in C++ they are called "templates" and in Ada "generics"; the expression "generic type" is not the best, somewhat confusing.)

I think the problem should be quite clear by now.

As to the solution… strictly speaking, there is no solution, because there is no a problem. I see nothing practically blocking in your case. The "pathological" case you show makes no practical sense, and non-trivial case will not allow getting field by reflection not because something prevents you to do that, but because it makes no sense at all.

The practical conclusion is: with GetValue, you always get some instance. And the instance is only possible if no partially-instantiated generic types are involved. Before getting any instance, or getting metadata required for instantiation, you need to fully instantiate the type(s) involved. This instantiation does not contradict your requirement to avoid instantiation of the instances of type (for the purpose of getting some "sample instance"), because generic type instantiation has nothing to do with type instantiation: generic type instantiation generates a type during compilation, but type instantiation generates and instance during run time. (Please see my comment to the question.)

I'm sure this Microsoft limitation does not impose any practical limitation to any non-nonsense architecture. If you don't think this is true, I would gladly discuss your architecture if you chose to share it with us, and if it does not take too much time.

—SA
 
Share this answer
 
v6
Comments
SoMad 11-Jul-12 22:15pm    
Now that is a great, detailed answer, +5. The code sample does look somewhat theoretical. I hope the OP will be able to adjust the design.

Soren Madsen
Sergey Alexandrovich Kryukov 11-Jul-12 22:28pm    
Thank you, Madsen.
I don't think if could be called "theoretical", but OP touches important layer of interesting issues. I feel he or she is qualified enough to understand things properly and hopefully to apply this understanding to the design.
--SA
SoMad 11-Jul-12 22:40pm    
I agree that OP seems qualified and I thought it was a good question too - gave it a 4.

Soren Madsen
Abhinav S 11-Jul-12 22:21pm    
Good answer. 5.
Sergey Alexandrovich Kryukov 11-Jul-12 22:25pm    
You certainly forgot this vote, but thank you very much for your good words.
--SA
if you have a requirement to dynamically add data to the generic you need to follow the methods followed by the List as creating IList and add data to the generic Please follow the same method and use the below link to add data dynamically to the list

http://www.codeproject.com/Articles/839024/csharp-list-reflection-Late-bound-operations-canno[^]
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900