2010-12-08 77 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(); 
    } 
} 
相關問題