2010-12-08 87 views
4

我想通过.Net反射调用一个构造函数,它将接口作为参数。这个类的代码看起来是这样的:.Net反射:如何调用一个构造函数,将接口作为参数

public interface IStringGetter 
{ 
    string GetString(); 
} 

public class Class1 
{ 
    private IStringGetter _stringGetter; 
    public Class1(IStringGetter stringGetter) 
    { 
     _stringGetter = stringGetter; 
    } 

    public String GetString() 
    { 
     return _stringGetter.GetString(); 
    } 
} 

使用这个类与反射的代码如下所示:

Assembly asm = Assembly.LoadFrom(@"c:\temp\ClassLibrary1.dll"); 
    Type tClass1 = asm.GetType("ClassLibrary1.Class1"); 
    Type tStringGetter = asm.GetType("ClassLibrary1.IStringGetter"); 

    ConstructorInfo ci = tClass1.GetConstructor(new Type[ ] { tStringGetter }); 
    // object obj = ci.Invoke(new object[ ] { *what goes here?* }); 

现在需要的是实现了IStringGetter接口对象。我无法获得具有反射的对象,因为库中没有实现该接口。有没有什么办法来创建一个实现接口并将其传递给构造函数的对象?

现在我正在使用Windows窗体与Visual Studio 2008,它是一个C#项目,目标。NET2.0框架。但我很高兴接受任何解决方案。

编辑:对不起,我没有在完整的上下文中说明问题。这两个代码片段位于不同的程序集中。包含第二个代码片段的程序集没有对第一个dll的引用,它只是用反射装载程序集。如果我只写

public class MyStringGetter : IStringGetter 

由于在编译时IStringGetter未知,编译器会引发错误。

EDIT2:虽然这不是我希望的,我想答案是:不要做

回答

0

即时创建新类绝非易事。正如@decyclone所说,你可以使用一个模拟库来创建一个库。

如果您需要更多地控制接口所做的工作,而不是模拟库提供的内容,您可能必须走下代码生成的路线。 System.Reflection.Emit命名空间中有专门用于在运行时创建代码的类。但他们并不是因为内心的淡淡。

4

如果没有在Assembly类实现此接口,创建mock,它在单独的Assembly中实现该接口并使用它。

+0

即使创建自己的存根类,只有空的接口方法声明可能足以启动,并且不需要模拟框架。只需创建自己的嵌套TestStringGetter类来实现接口,创建一个实例并将其传递给Invoke。 – 2010-12-08 09:36:00

+0

是的,我没有字面意思是使用Mocking框架。任何简单的模拟都可以。正如蒂姆所说。 – decyclone 2010-12-08 09:42:54

+0

为了确保我能理解你:在包含实现接口的类的新程序集中,我必须包含对ClassLibrary1.dll的引用,以便我可以使用“正常”继承? – 2010-12-08 13:56:42

-1

我觉得

您可以使用Activator.CreateInstance,请参见下面的方法decalaration

// Summary: 
    //  Creates an instance of the specified type using the constructor that best 
    //  matches the specified parameters. 
    // 
    // Parameters: 
    // type: 
    //  The type of object to create. 
    // 
    // args: 
    //  An array of arguments that match in number, order, and type the parameters 
    //  of the constructor to invoke. If args is an empty array or null, the constructor 
    //  that takes no parameters (the default constructor) is invoked. 
    // 
    // Returns: 
    //  A reference to the newly created object. 
    // 
    // Exceptions: 
    // System.ArgumentNullException: 
    //  type is null. 
    // 
    // System.ArgumentException: 
    //  type is not a RuntimeType. -or-type is an open generic type (that is, the 
    //  System.Type.ContainsGenericParameters property returns true). 
    // 
    // System.NotSupportedException: 
    //  type cannot be a System.Reflection.Emit.TypeBuilder.-or- Creation of System.TypedReference, 
    //  System.ArgIterator, System.Void, and System.RuntimeArgumentHandle types, 
    //  or arrays of those types, is not supported. -or-The constructor that best 
    //  matches args has varargs arguments. 
    // 
    // System.Reflection.TargetInvocationException: 
    //  The constructor being called throws an exception. 
    // 
    // System.MethodAccessException: 
    //  The caller does not have permission to call this constructor. 
    // 
    // System.MemberAccessException: 
    //  Cannot create an instance of an abstract class, or this member was invoked 
    //  with a late-binding mechanism. 
    // 
    // System.Runtime.InteropServices.InvalidComObjectException: 
    //  The COM type was not obtained through Overload:System.Type.GetTypeFromProgID 
    //  or Overload:System.Type.GetTypeFromCLSID. 
    // 
    // System.MissingMethodException: 
    //  No matching public constructor was found. 
    // 
    // System.Runtime.InteropServices.COMException: 
    //  type is a COM object but the class identifier used to obtain the type is 
    //  invalid, or the identified class is not registered. 
    // 
    // System.TypeLoadException: 
    //  type is not a valid type. 
    public static object CreateInstance(Type type, params object[] args); 
1

要么与null调用它:

object obj = ci.Invoke(new object[ ] { null }); 

或实例的类型实现该接口:

IStringGetter sg = new StringGetterImpl(); 
object obj = ci.Invoke(new object[ ] { sg }); 

如果在您的解决方案没有类型实现该接口,你将不得不在代码中定义的实现或动态生成对实现该接口类型(可以动态代理生成与Spring.NET框架例如)。

0

很久以前,但尝试做这样的事情。

class DoClassInvoke 
{ 
    public void InvokeConstructorHaveInterfaceAsParameter() 
    { 
     var class1Type = typeof(Class1); 
     var mainParamConstructor = SummonParameter(class1Type); 
     var mainConstructor = class1Type.GetConstructors().FirstOrDefault(); 
     var mainConstructorDeclare = mainConstructor.Invoke(mainParamConstructor); 
     var mainMethod = class1Type.GetMethod("GetString"); 
     var mainValue = mainMethod.Invoke(mainConstructorDeclare, new object[] { }); 
    } 

    private object[] SummonParameter(Type classTypeData) 
    { 
     var constructorsOfType = classTypeData.GetConstructors(); 
     var firstConstructor = constructorsOfType.FirstOrDefault(); 
     var parametersInConstructor = firstConstructor.GetParameters(); 
     var result = new List<object>(); 
     foreach (var param in parametersInConstructor) 
     { 
      var paramType = param.ParameterType; 
      if (paramType.IsInterface) 
      { 
       var implClassList = AppDomain.CurrentDomain.GetAssemblies() 
        .SelectMany(s => s.GetTypes()) 
        .Where(w => paramType.IsAssignableFrom(w) & !w.IsInterface).ToList(); 

       var implClass = implClassList.FirstOrDefault(); 

       var parameteDatar = SummonParameter(implClass); 

       var instanceOfImplement = (parameteDatar == null || parameteDatar.Length == 0) 
        ? 
        Activator.CreateInstance(implClass) 
        : 
        Activator.CreateInstance(implClass, parameteDatar); 

       result.Add(instanceOfImplement); 
      } 
     } 
     return result.ToArray(); 
    } 
} 
相关问题