2009-10-19 61 views
3

我试图给我们的Io​​C容器添加通用服务支持,并且我有一个问题。C#中通用类型构造函数的解析,IoC中使用通用服务注册

比方说,我有以下类型:

public interface IService<T> { ... } 
public class Service<T> : IService<T> { ... } 

,然后将下面的代码:

Type type = typeof(Service<>); // <-- notice no specific type here 
ConstructorInfo ctor = LogicToFindCtor(type); // <-- picks one of the ctors 

现在,在这一点,我有一个通用的类型,我不能调用构造函数,因为它是通过具有泛型参数的泛型类型获得的。

所以,因为在我的代码我试图解决一个特定的类型,说IService<Employee>,我可以很容易地通过我的代码,我需要使用的具体类型Service<T>解决这一发现,那我需要注入输入Employee代替T

但是,我的问题是这样的:鉴于我有我想调用的ctor已经制定了通用的非特定类型,我如何找到特定类型的正确构造函数。

Type specificType = typeof(Service<Employee>); 
ConstructorInfo specificCtor = MapGenericToSpecific(ctor, specificType); 

编辑:我注意到,财产MetaDataToken两个构造函数(一个从非特定类型和特定类型的)具有相同的价值在这里,我可以用它来搭配?它仍然需要一个循环来找到正确的构造函数,但是用一个简单的if语句找到正确的构造函数的循环远比看看参数并尝试匹配这种方式更合适。我已经更改了下面的代码。这现在编译和运行,是否有更好的方法,甚至更少的反射,也许直接查找构造函数表中找到基于metadatatoken值的构造函数?

下面的代码:

using System; 
using System.Linq; 
using System.Reflection; 
using System.Diagnostics; 
namespace ConsoleApplication10 
{ 
    public class ActivationAttribute : Attribute { } 

    public class TestClass<T1, T2> 
    { 
     public TestClass(String p1) 
     { 
      Console.Out.WriteLine("Wrong constructor"); 
     } 

     [Activation] 
     public TestClass(T1 p1) 
     { 
      Console.Out.WriteLine("Right constructor, p1=" + p1); 
     } 

     public TestClass(T2 p2) 
     { 
      Console.Out.WriteLine("Wrong constructor"); 
     } 

     public TestClass() 
     { 
      Console.Out.WriteLine("Wrong constructor"); 
     } 

     public TestClass(T1 p1, T2 p2) 
     { 
      Console.Out.WriteLine("Wrong constructor"); 
     } 

     public TestClass(String p1, T2 p2) 
     { 
      Console.Out.WriteLine("Wrong constructor"); 
     } 

     public TestClass(String p1, Int32 p2) 
     { 
      Console.Out.WriteLine("Wrong constructor"); 
     } 
    } 

    public class Program 
    { 
     static void Main(string[] args) 
     { 
      // This is the type I have in my IoC container 
      Type genericType = typeof(TestClass<,>); 

      // This is the constructor I locate 
      ConstructorInfo genericCtor = 
       (from ctor in genericType.GetConstructors() 
       where ctor.IsDefined(typeof(ActivationAttribute), false) 
       select ctor).First(); 
      Debug.Assert(genericCtor != null); 

      // RESOLUTION STEP 

      // Upon resolution, two actual types are specified 
      Type[] genericArguments = new Type[] { typeof(String), typeof(Int32) }; 

      // So I create the actual type from the generic one 
      Type specificType = genericType.MakeGenericType(genericArguments); 

      // Can I look up the "genericCtor.MetadataToken" property directly? 
      // or is this as good as it gets? 
      ConstructorInfo specificCtor = 
       (from ctor in specificType.GetConstructors() 
       where ctor.MetadataToken == genericCtor.MetadataToken 
       select ctor).First(); 
      Debug.Assert(specificCtor != null); 

      Debug.Assert(specificCtor != null, "No matching constructors was found"); 
      Object instance = specificCtor.Invoke(new Object[] { "Test" }); 

      Console.Out.Write("Press enter to exit..."); 
      Console.In.ReadLine(); 
     } 
    } 
} 

回答

2

可以依靠MetadataToken保持不变的有界和无界构造。元数据是用IL代码创建的,它是类型的一部分,与通用参数绑定无关。

.NET不会为每个泛型参数的使用创建不同的类型(例如List<int>List<bool>)。它是相同的类型,但在每次调用时,有限的泛型参数都通过方法参数传递给堆栈(我知道您可能已经知道所有这些,但我只是确认)。

因此,MetadataToken当类泛型参数绑定到特定类型时,附加到该类型在运行时不会更改。例如:

bool unboundAndBoundHasSameMetadataToken = 
      typeof(IList<>).MetadataToken == typeof(IList<int>).MetadataToken; 

bool boundedClassesHasSameMetadataToken = 
      typeof(IList<bool>).MetadataToken == typeof(IList<int>).MetadataToken; 

Assert.IsTrue(unboundAndBoundHasSameMetadataToken); 
Assert.IsTrue(boundedClassesHasSameMetadataToken); 

底线,MetadataToken是IL“的一部分”和相同类型具有不同的通用参数结合的实例没有什么不同。


出于好奇,(我可能失去了一些东西),为什么不使用发现有界类型激活构造它的绑定类型中找到的相同,是过滤?激活属性也修饰了有界的构造函数。

+0

请原谅我的无知,但是当你说“有界和无界的构造函数”时,实际上有什么区别? (我知道我可能没有使用正确的术语,而你的可能是正确的)你的意思是,我发现我的泛型类型的构造函数,当我还不知道T的实际类型(无界),与我需要为特定类型定位的构造函数相比,当我知道T的类型时?再次,请原谅我缺乏使用正确的术语,因为我不知道如何准确地描述我的意思。 – 2009-10-30 23:19:03

+0

...和[Activation]属性上的良好通话....(打头像)不知道为什么我没有想到... – 2009-10-30 23:20:08

+0

但是,只是为了得到这个直线,你是说如果我检查'SomeGenericType(T)'类型,我仍然不知道T的类型,与'SomeGenericType(T)'的* specific *类型相比,方法将具有相同的MetadataToken值? (例如,值不取决于T的类型?) – 2009-10-30 23:22:19

相关问题