繁体   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