在 C# 中使用反射返回实例


下面

给出了我试图返回类实例的示例代码。

public object getConstructorclass(int i)
{  
    if(i==1)
    {
       Type type = Type.GetType("test1");
    }else
    {
       Type type = Type.GetType("test2");
    }
    return Activator.CreateInstance(type); 
}    
var objcls = getConstructorclass(1);
objcls.callclass();//error occured

我怎么能在这里提到类类型,因为该类型在编译时是未知的,但它会在运行时决定。在上面的例子中,我只传递一个值 1(它可以是任何东西,并且该类将被相应地调用(,然后调用类 test1。

在这里,我将在第 objcls.callclass() 行上收到错误,因为objcls是一个没有callclass()方法的object实例。

如何重构这段代码?我的目标是如果我在 getConstructorclass() 方法中提到一个类,应该返回一个对象,以便在进一步的代码中使用它来调用该类的成员。

如果你知道你的类将有这个方法,你应该为它们使用一个通用接口并相应地实现它。然后,您将使用已确保它正常工作的类。

它看起来像这样

IMyInterface objcls = getconstrorclass() as IMyInterface;
if (objcls != null)
    objcls.callclass();
else
    // we failed miserably and should do something about it

我认为如果你的类没有任何共同点,你不应该使用一些基于 int 变量的通用对象返回构造函数。像这样处理它真的很奇怪,它可能会导致各种问题(其中一些您目前已经遇到(。如果类在某种程度上相关,并且您可以预测结果,但要创建一个全能方法,则泛型类构造函数是有意义的。不太确定这种方法的正确性。

无论如何,如果您坚持(不推荐,但如您所愿(,您可以为如下所示的类型创建一些检查:

var createdObject = getConstructorclass(1);
if (createdObject is MyClass1)
{
    var specificObject = (MyClass1)createdObject;
    specificObject.callMethod1(); 
}
else if (createdObject is MyClass2)
{
    var specificObject = (MyClass2)createdObject;
    specificObject.callSomeOtherMethod();
}
...

但它很快就会变得非常容易出错,重构可能会是一场噩梦等,但这是你的决定。

或者你可以使用pwas的解决方案,但对我来说,对于这样一个基本任务来说,这似乎不必要地复杂。看起来不错,但它仍然只返回类型"object",因此它并不能真正解决您的特定问题。

另外,为了解决一个问题,我不确定您是否理解 - 您已经创建了实例,您只需返回类型对象。这就是为什么你不能在这个对象上调用任何特定的方法,因为首先你必须把它强制转换为实际上具有该方法的东西,并确保可以完成强制转换(继承等(。

如果interface解决方案(见其他答案(就足够了,不要看这个答案。当您无法使用公共基类/接口并且仍然需要调用成员时,您可以使用带有is关键字(和检查类型(的解决方案。您可以使用流畅的 API,而不是为每个情况编写许多 if:

object obj = this.getConstructorclass();
obj.StronglyInvoke()
   .When<int>(value => Console.WriteLine("Got {0} as int", value))
   .When<string>(value => Console.WriteLine("Got {0} as string", value))
   .OnFail(() => Debug.Write("No handle."))
   .Invoke();

溶液:

public class GenericCaller
{
    private IList<GenericInvoker> invokers = new List<GenericInvoker>();
    private readonly object target;
    private Action failAction;
    public GenericCaller(object target)
    {
        if (target == null)
        {
            throw new ArgumentNullException("target");
        }
        this.target = target;
    }
    public GenericCaller OnFail(Action fail)
    {
        this.failAction = fail;
        return this;
    }
    public GenericCaller When<T>(Action<T> then)
    {
        if (then == null)
        {
            throw new ArgumentNullException("then");
        }
        var invoker = new GenericInvoker<T>(this.target, then);
        this.invokers.Add(invoker);
        return this;
    }
    public void Invoke()
    {
        if (this.invokers.Any(invoker => invoker.Invoke()))
        {
            return;
        }
        if (this.failAction == null)
        {
            throw new InvalidOperationException("Handler not found");
        }
        this.failAction();
    }
    public abstract class GenericInvoker
    {
        protected readonly object target;
        protected GenericInvoker(object target)
        {
            this.target = target;
        }
        public abstract bool Invoke();
    }
    public class GenericInvoker<T> : GenericInvoker
    {
        private readonly Action<T> then;
        public GenericInvoker(object target, Action<T> then)
            : base(target)
        {
            this.then = then;
        }
        public override bool Invoke()
        {
            if (this.target.GetType() == typeof(T))
            {
                this.then((T)this.target);
                return true;
            }
            return false;
        }
    }
}
public static class Extensions
{
    public static GenericCaller StronglyInvoke(this object o)
    {
        return new GenericCaller(o);
    }
}

Remeber - 使用通用界面会更优雅(如其他答案所说( - 我的只是替代方法。

将变量声明为动态

变量
dynamic objcls = getconstrorclass();

使用它,将在运行时确定,无论getconstrorclass方法返回什么。您可以访问该类型的任何成员,并且在编译时不会收到任何错误。但是,如果您尝试访问不存在的成员,您将在运行时获得RuntimeBinderException

我建议使用interface并将可以以这种方式实例化的类限制为仅实现接口的类。

public interface IMyInterface
{
    void callclass();
}
public <T> getConstructorClass()
{
    T instance;
    Type type = Type.GetType("test1");
    // instance will be null if the object cannot be cast to type T.
    instance = Activator.CreateInstance(type) as T;
    return T;
}
IMyInterface objcls = getConstructorClass<IMyInterface>();
if(null != objcls)
{
    objcls.callclass();
}
不确定

你最终想要实现什么,但这看起来像是"依赖注入"的工作 - 这是一个使用 autofac 的不错示例

相关内容

  • 没有找到相关文章

最新更新