C#反射来自通用基类中的字段的GetValue [英] C# reflection GetValue from a field in generic base class

查看:95
本文介绍了C#反射来自通用基类中的字段的GetValue的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题在于我们不能只存在于具有泛型类型的基类中的字段(非泛型)的GetValue。

请参阅下面的代码片段。调用

 f.GetValue(a)

将抛出带有消息的异常:无法对Type.ContainsGenericParameters为true的类型的字段执行后期绑定操作。



  class 计划
{
< span class =code-keyword> static void Main( string [] args)
{
类型abstractGenericType = typeof (ClassB<>);
FieldInfo [] fieldInfos =
abstractGenericType.GetFields(BindingFlags.Public | BindingFlags.Instance);

ClassA a = new ClassA( 你好);
foreach (FieldInfo f in fieldInfos)
{
f。 GetValue(a); // 抛出InvalidOperationhException
}
}
}

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

内部 ClassA: ClassB的<字符串>
{
public ClassA( string ): base value
{}
}





我们的设计要求我们在拥有任何实际对象实例之前先获取FieldInfo。所以我们不能使用



类型typeA = abstractGenericType.MakeGenericType( typeof  string )); 
FieldInfo [] fieldInfos = typeA.GetFields();



谢谢

解决方案

啊, 终于我明白了。也许是一个有趣的问题,但没有多大意义。



这就是事情:你面临着一些不是100%逻辑上要求的限制。你的代码样本看起来很有说服力(没有多少人会真正理解你对它的解释,恰好我现在忙于处理相关的事情:-))。谁知道为何应用这种限制?也许只有那些做出这个决定的人。



尽管如此,这种限制使完美的实践意义。我会用这种方式推测:那些微软人刚刚决定:我们不想处理那些几乎无法提供很多实际意义的病态案例。你明白我的意思是什么吗?查看 ClassB 。这是一种泛型类型,其中不使用泛型参数。这种情况在某种意义上是病态的,我将在稍后解释。



首先,想象你省略了泛型参数。很明显,你的 GetValue 在这种情况下有效。它从不使用泛型参数,你可以轻松地删除它。从理论上讲,我可以想象系统会将这种病态类型视为等同于没有通用参数的终端(实例化)类型。但是,它会使系统更复杂,更难理解。所有违规行为特殊情况通常都是不好的。抛出你观察到的异常总是更好,也更容易理解。



现在,另一方面,想象实际使用泛型参数。如果它在 fieldInfos 的字段中使用,那么绝对显而易见的是,您的代码无论如何都没有任何意义。实际上, GetValue 的返回结果是编译时类型 System.Object ,但它应该有一些运行 - 时间类型,应该是类型 T 哪个...不存在,因为您的元数据是从不完整的(通用)类型 ClassB获得的



我甚至认为在理论上可以使用 GetValue 即使 fieldInfos 的所有字段都是非泛型字段。 (这可能是因为你只接受公众成员,根据你的 BindingFlags ,所以只有一些非公开成员可能是通用的。)这很难看,但我的想法是这个:关键的事实是 ClassB 不是类型,所以它没有一定的内存布局。泛型参数的大小未知,因此实现 GetValue 可能是不可行的,因为即使是非泛型类型的内存偏移也是未知的。它需要进一步详细说明,但至少它看起来对我来说是一个真正的障碍。



这里的关键问题是你使用的是通用类型的元数据使用真实(完全实例化,非泛型)类型的实例。这两种类型不相关: ClassA ClassB< string> 兼容,但与不兼容ClassB<> ,根本不能拥有实例。泛型类型根本不是类型。 (术语泛型类型表明它是,因为它建议声明泛型类型是一种类型,这是不正确的;难怪在C ++中它们被称为模板和Ada泛型;表达式泛型不是最好的,有点令人困惑。



我认为问题现在应该很清楚了。



至于解决方案......严格来说,没有解决方案,因为没有问题。在你的情况下我没有看到任何实际阻塞。你所展示的病态案例没有任何实际意义,并且非平凡的案例不允许通过反思获取字段不是因为某些东西阻止你这样做,而是因为它根本没有任何意义。 br />


实际的结论是:使用 GetValue ,你总能获得一些实例。只有在不涉及部分实例化的泛型类型时才能实例化。在获取任何实例或获取实例化所需的元数据之前,您需要完全实例化所涉及的类型。这个实例化并不反对你要求避免实例化类型实例(为了得到一些样本实例),因为泛型类型实例化与类型实例化无关:泛型类型实例化在编译期间生成一个类型,但是类型实例化在运行时生成和实例。 (请参阅我对该问题的评论。)



我确信此Microsoft限制不会对任何非废话架构施加任何实际限制。如果您不认为这是真的,如果您选择与我们分享,如果不花太多时间,我很乐意讨论您的架构。



-SA


如果您需要动态地向通用添加数据,则需要按照List所遵循的方法创建IList并将数据添加到通用请按照相同的方法,并使用以下链接动态添加数据到列表



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

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

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.

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

解决方案

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


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


这篇关于C#反射来自通用基类中的字段的GetValue的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆