2

因此,之前已经在 SO 上讨论过这个问题,但是我认为我没有真正看到过为什么会发生这种情况的解释,我似乎也无法了解这对尝试在代码中使用反射的普通开发人员有何用处。

所以检查一下这段代码。

var fields = typeof(Person).GetFields(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance);

如果我的对象List<int>中有一个,Person那么我将取回一个反射“名称”设置为的字段List`1,或者如果我有一本字典,它将是Dictionary`2。从表面上看,这似乎很难处理,我不能说以下

foreach (var fieldInfo in fields.Where(fieldInfo => fieldInfo.FieldType == typeof(List<int>)))
{
     //Do something.
}

出现这种情况的原因是因为我在我目前正在从事的项目中发现了以下内容。

    //Initialize collections
    FieldInfo[] properties = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance);
    foreach (FieldInfo f in properties)
    {
       if (f.FieldType.Name == "IList`1" && f.GetValue(obj) == null)
       {
             object value = Container.Resolve(f.FieldType);
             f.SetValue(obj, value);

       }
   }

然后在统一的配置中我看到了这种幸福

<alias alias="IList`1" type="System.Collections.Generic.IList`1, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>

我真的不知道我知道这很糟糕?是吗?它当然有效,但即使这没问题(这会导致我的可疑代码 dar 消失),我最初的问题仍然存在。作为程序员,关于泛型的维度信息对我们有什么好处?

4

2 回答 2

3

它当然不是为了帮助程序员。它在那里是因为 CLI 需要它。进一步的理由是,它确保具有相同标识符名称但类型参数数量不同的泛型类型具有唯一的类型名称。来自 ECMA 335 规范的一些措辞:

CLS 规则 43:根据上面定义的规则,泛型类型的名称应编码在非嵌套类型上声明的类型参数的数量,或者如果嵌套,则新引入类型。[注意:CLS(消费者):不需要消费违反此规则的类型。CLS(扩展器):与消费者相同。选择支持泛型类型定义的扩展程序应遵循外部可见类型的此规则。CLS(框架):不应公开违反此规则的类型。尾注]

在第 II.9 节中进行了一些澄清:

泛型类型由名称后跟以 <…> 分隔的泛型参数列表组成,如C<T>. 两个或多个泛型类型不应在同一范围内定义为具有相同名称但具有不同数量的泛型参数。但是,为了允许在源语言级别对泛型数量进行此类重载,定义 CLS 规则 43 以将泛型类型名称映射到唯一的 CIL 名称。该规则规定,具有一个或多个泛型参数的类型 C 的符合 CLS 的名称应具有形式的后缀`n,其中 n 是十进制整数常量(不带前导零),表示 C 具有的泛型参数的数量。例如:类型C, C<T>, 和C<K,V>具有 CLS 兼容的名称C, C 1<T>, andC2<K,V>, 分别。[注意:所有标准库类型的名称都符合 CLS;例如,System.Collections.Generic.IEnumerable`1。尾注]

抱歉,没有以正确的方式出现,发布答案时反引号很棘手。查看 ECMA 文档的准确性。

于 2012-10-26T13:46:35.740 回答
2

当您处理在编译时已知的类型时,您永远不需要处理NameType,因此诸如此类的名称Thing`n不应该成为问题。

我不确定您的第一个示例中发生了什么,就像我这样做时一样:

class Person
{
    private List<int> intList;
}

和这个:

class Program
{
    static void Main(string[] args)
    {
        var fields = typeof(Person).GetFields(BindingFlags.DeclaredOnly 
                                            | BindingFlags.NonPublic 
                                            | BindingFlags.Instance);

        foreach (var fieldInfo in 
            fields.Where(fieldInfo => fieldInfo.FieldType == typeof(List<int>)))
        {
            Console.WriteLine(fieldInfo.ToString());

        }
    }
}

我得到了我所期望的,即

System.Collections.Generic.List`1[System.Int32] intList

在您提供的代码示例中,类型在编译时也是已知的;比你展示的更好

//Initialize collections
FieldInfo[] properties = type.GetFields(BindingFlags.DeclaredOnly 
                                      | BindingFlags.NonPublic 
                                      | BindingFlags.Instance);
foreach (FieldInfo f in properties)
{
   if(typeof(IList<int>).IsAssignableFrom(f.FieldType)
   && f.GetValue(obj) == null)
   {
         object value = Container.Resolve(f.FieldType);
         f.SetValue(obj, value);
   }
}

知道什么是a IList<int>;您可以根据需要使用IsAssignableFrom==

(如果您IsAssignableFrom像我一样对 感到困惑,请记住:if (a is b)与 是相同的测试if (typeof(b).IsAssignableFrom(a.getType()))。订单交换轮次。

于 2012-10-26T14:04:02.113 回答