Click here to Skip to main content
11,802,762 members (72,925 online)
Rate this: bad
Please Sign up or sign in to vote.
See more: C# Generics reflection
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
will throw the exception with message: Late bound operations cannot be performed on fields with types for which Type.ContainsGenericParameters is true.

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

Type typeA = abstractGenericType.MakeGenericType(typeof(string));
FieldInfo[] fieldInfos = typeA.GetFields();
Thank you
Posted 11-Jul-12 12:55pm
Sergey Alexandrovich Kryukov at 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.)
Rate this: bad
Please Sign up or sign in to vote.

Solution 1

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 Smile | :) ). 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.

SoMad at 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 at 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.
SoMad at 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 at 11-Jul-12 22:21pm
Good answer. 5.
Sergey Alexandrovich Kryukov at 11-Jul-12 22:25pm
You certainly forgot this vote, but thank you very much for your good words.
Damith Weerasinghe at 11-Jul-12 22:53pm
my 5+, detailed answer, keep it up SA. :)
Sergey Alexandrovich Kryukov at 11-Jul-12 23:18pm
Thank you, Damith.
Prasad_Kulkarni at 12-Jul-12 0:09am
Well explained SA, +5!
Sergey Alexandrovich Kryukov at 12-Jul-12 0:25am
Thank you, Prasad.
Member 9242374 at 12-Jul-12 14:40pm
Thank you for your thorough explanation, the generic parameter in ClassB is indeed used in some other instance variables in ClassA but I did not include them to keep the sample short. And in the real case, we only want to fetch the value using one specific non generic type FieldInfo instead of iterate through all the fields. someone ported the whole architecture to C# from java so it does seems to need some tweak.
Sergey Alexandrovich Kryukov at 12-Jul-12 16:25pm
You are very welcome.
Good luck, call again.
BillWoodruff at 6-Nov-14 11:18am
+5 Excellent, thorough, analysis.
Sergey Alexandrovich Kryukov at 6-Nov-14 11:42am
Thank you very much, Bill.
It's interesting that you came across these pretty old question and answer which I did not remember already.
BillWoodruff at 6-Nov-14 13:04pm
Well, I could say that your mind is "timeless" :) but, that would be ... jejeune: this question must have popped up in the current 'Active list for this forum because Sai Raj responded today ? Or, did destiny lead me to it ?
Sergey Alexandrovich Kryukov at 6-Nov-14 13:13pm
Ah... Come to think about, Sai Raj and "destiny" is the same... :-)
Rate this: bad
Please Sign up or sign in to vote.

Solution 2

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[^]

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

  Print Answers RSS
0 KrunalRohit 366
1 OriginalGriff 365
2 F-ES Sitecore 295
3 CPallini 270
4 Sergey Alexandrovich Kryukov 239
0 OriginalGriff 2,950
1 Maciej Los 1,910
2 KrunalRohit 1,862
3 CPallini 1,695
4 Richard MacCutchan 1,157

Advertise | Privacy | Mobile
Web04 | 2.8.151002.1 | Last Updated 6 Nov 2014
Copyright © CodeProject, 1999-2015
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100