从封闭版本获取通用构造函数(Net Standard 1.1)

时间:2017-11-22 23:11:42

标签: c# .net generics .net-standard

我将首先链接this question,它显示了一种方法来做我想做的事情 - 不幸的是,它在.Net Standard 1.1中是不可能的。

虽然我需要这个适用于任何泛型类型,但这是一个示例类型:

class MyGeneric<T>
{
   public MyGeneric(T a1, string a2) { }
   public MyGeneric(T a1, double a2) { }
}

我想要一个函数,当提供ConstructorInfo 具体 MyGeneric<>时,例如:

  • MyGeneric<int>..ctor(int, double)

将为同一个构造函数返回另一个ConstructorInfo,但是对于未绑定的泛型类型MyGeneric<>而言:

  • MyGeneric<T>..ctor(T, double)
  

然后,目的是能够采用另一种方式 - 即给定MyGeneric<T>..ctor(T, double),我可以获得该通用的任何绑定/封闭版本的相同构造函数 - 例如MyGeneric<DateTime>..ctor(DateTime, double)MyGeneric<Foo>..ctor(Foo, double)

     

当泛型类型参数在构造函数签名中作为另一个泛型的类型参数出现时,它也必须工作 - 例如MyGeneric(IEnumerable<T>)

我能找到的最佳实现是上面的链接,它使用MethodBase.GetMethodFromHandle(RuntimeMethodHandle, RuntimeTypeHandle)

return (ConstructorInfo)MethodBase.GetMethodFromHandle(
           ctor.MethodHandle, 
           ctor.DeclaringType.GetGenericTypeDefinition().TypeHandle);

(假设ctor包含对具体泛型类型的构造函数版本的引用)

这适用于所有类型的所有构造函数,无论泛型类型自身类型参数与构造函数参数类型之间的关系有多古怪。

但是,虽然.netstandard1.1 确实具有MethodBase.GetMethodFromHandle静态方法,但似乎没有办法从{{1}获取RuntimeMethodHandle对象(即MethodInfo基类MethodHandle上没有MethodBase属性。

所以我觉得这样做是不可能的。

.Net Standard 1.1的当前实施

目前,我对.Net Standard 1.1的实现假定Constructorinfo(或Type)为开放式通用返回的成员顺序与任何已关闭的通用内容返回的成员顺序相同从它:

TypeInfo

注意var position = Array.IndexOf( TypeHelpers.GetConstructors(ctor.DeclaringType), ctor); if(position >= 0) { return TypeHelpers.GetConstructors( ctor.DeclaringType.GetGenericTypeDefinition())[position]; } 方法仅根据目标框架使用旧的或更新的反射API返回类型的公共构造函数

一旦我知道了索引,然后我重新使用它来从开放泛型的构造函数映射回到封闭的构造函数,用于从该开放泛型构建的任何闭合/绑定泛型。

这似乎有用( 有警告,请参阅下一页 ),有点有意义(因为所有具体的泛型应该逻辑上'继承' '所有字段/方法元数据按相同顺序列出) - 但感觉不对,因为我们永远依赖于从任何反射API返回的结果的顺序。

注意事项 上述基于TypeHelpers.GetConstructors的解决方案间歇性地 ,因为每当使用TypeInfo API时,它都依赖于ConstructorInfo缓存,因此您可以比较引用相等性构造函数。但结果并非总是如此!

更好的方法?

有更好的方法吗?是否可以从.NetStandard 1.1中的DeclaredConstructors获取RuntimeMethodHandleRuntimeTypeHandle - 或者我是否应该像第二个代码示例一样搜索方法/构造函数的数组?

看起来很奇怪.NetStandard 1.1有ConstructorInfo重载,但似乎没有提供任何方法来获取你需要的句柄作为参数!

1 个答案:

答案 0 :(得分:0)

我仍处于核心反思的学习曲线上,但请看下面的例子,看看它是否有帮助。

//assumes ctor contains a reference to the 
//concrete generic type's version of the constructor
public Type GetDeclaringType(ConstructorInfo ctor) {
    var type = ctor.DeclaringType;//Gets the class that declares this member.
    var typeInfo = type.GetTypeInfo();//Returns TypeInfo representation of specified type.
    if (typeInfo.IsGenericType) {
        type = typeInfo.GetGenericTypeDefinition();
    }
    return type;
}

所以假设ctor是MyGeneric<DateTime>..ctor(DateTime, double)

var declaredType = GetDeclaringType(ctor); //MyGeneric<>
var closedType = declaredType.MakeGenericType(typeof(int));//MyGeneric<int>
//constructors
var typeInfo = closedType.GetTypeInfo();
var constructors = typeInfo.GetConstructors();
//MyGeneric<int>..ctor(int, double)
var constructorWithDouble = constructors
    .Where(ctor => ctor.GetParameters().Skip(1).First().ParameterType == typeof(double))
    .First();