簡體   English   中英

.Net 反射:如何調用以接口為參數的構造函數

[英].Net Reflection: How to invoke a constructor that takes a interface as parameter

我想通過 .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 接口的對象。 我無法通過反射獲取對象,因為庫中沒有任何內容實現該接口。 有沒有辦法創建一個實現接口的對象並將其傳遞給構造函數?

現在我在 Visual Studio 2008 中使用 Windows 窗體,它是一個面向 .Net2.0 框架的 C# 項目。 但我很樂意接受任何解決方案。

編輯:對不起,我沒有在完整的上下文中說明問題。 這兩個代碼片段位於不同的程序集中。 包含第二個代碼片段的程序集沒有對第一個 dll 的引用,它只是通過反射加載程序集。 如果我只是寫

public class MyStringGetter : IStringGetter

編譯器拋出錯誤,因為 IStringGetter 在編譯時未知。

Edit2 :雖然這不是我所希望的,但我認為答案是:不要那樣做

如果Assembly沒有實現此接口的類,請創建一個在單獨的Assembly中實現該接口的mock並使用它。

要么用null調用它:

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

或者實例化一個實現該接口的類型:

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

如果您的解決方案中沒有實現該接口的類型,您將必須在代碼中定義一個實現或動態生成一個實現該接口的類型(例如,您可以使用 Spring.NET 框架動態代理生成)。

很久以前,但嘗試做這樣的事情。

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();
    }
}

動態創建新類從來都不是一項簡單的任務。 正如@decyclone 所說,您可以使用模擬庫來創建一個。

如果您需要比模擬庫更多地控制接口的功能,您可能不得不沿着代碼生成路線走下去。 System.Reflection.Emit 命名空間中有專門用於在運行時創建代碼的類。 但它們不適合膽小的人。

我知道我參加聚會有點晚了,但我認為所有的答案都走錯了路。 我假設您想使用可在整個類中訪問的預定義​​的已初始化字段集來實例化該類。 在這種情況下,請執行以下操作:

全局字段

private IInterface1 IInterface1;
private IInterface2 IInterface2;

構造函數

public Constructor(IInterface1 iInterface1, IInterface2 iInterface2)
{
    this.IInterface1 = iInterface1?? throw new ArgumentNullException(nameof(iInterface1));
    this.IInterface2 = iInterface2?? throw new ArgumentNullException(nameof(iInterface2));
}

方法(反射)

Type classType = typeof(ClassName);
object[] constructorParameters = new object[]
{
    IInterface1,
    IInterface2
};
var instance = Activator.CreateInstance(classType, constructorParameters);

另一種可能適用於需要基於接口創建具體類型的情況的方法是讓調用者注冊知道類型或任何接口的構建器。

然后,當您需要一個具體類型時,您可以查看已注冊的項目,然后使用已注冊的具體類型或其構建器來創建它。

MyLib.RegisterType(typeof(IImmutablePerson), typeof(ImmutablePerson))

我認為

您可以使用 Activator.CreateInstance ,請參閱下面的方法聲明

// 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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM