简体   繁体   English

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

[英]Return instance using reflection in C#

A sample code I tried to return an instance of class is given below. 下面给出了我尝试返回类实例的示例代码。

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

How can I mention the class type here since the type is not known at compile time but it will decided at runtime.In the above example i just pass a value 1 (it can be anything and that class will be called accordingly), and the class test1 called. 我如何在这里提到类类型,因为该类型在编译时未知,但它将在运行时决定。在上面的示例中,我只是传递了一个值1(它可以是任何值,并且该类将被相应地调用),并且类test1被调用。

here I will get an error on the line objcls.callclass() , because objcls is an object instance that doesn't have a callclass() method. 在这里,我会在objcls.callclass()行上objcls.callclass()错误,因为objcls是一个没有callclass()方法的object实例。

How can I restructure this piece of code? 我如何重组这段代码? My aim is if I mention a class in the getConstructorclass() method, an object should be returned so as to use it in the further code to invoke the members of that class. 我的目的是,如果我在getConstructorclass()方法中提到一个类,则应返回一个对象,以便在进一步的代码中使用该对象来调用该类的成员。

If you know that your classes will have this method, you should use a common interface for them and implement it accordingly. 如果您知道您的类将使用此方法,则应为其使用通用接口并相应地实现它。 Then you will work with classes that you have made sure it will work. 然后,您将使用确保它可以正常工作的类。

It would look like this 看起来像这样

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

I don't think you should use some generic object returning constructor based on an int variable, if your classes don't have anything in common. 如果您的类没有任何共同点,我不认为您应该使用基于int变量的通用对象返回构造函数。 It's really weird to handle it like this and it may lead to various problems (some of which you're currently already experiencing). 像这样处理它真的很奇怪,它可能会导致各种问题(其中一些您目前已经遇到过)。 Generic class constructors make sense if the classes are somewhat related and you can predict the outcome, but to create a do-it-all method.. Not so sure about correctness of such approach. 如果类之间有些关联,并且可以预测结果,则通用类构造函数很有意义,但是您可以创建一个“万事俱备”的方法。不确定这种方法的正确性。

Anyway, if you insist (not recommended, but as you wish), you can create some checks for a type like this: 无论如何,如果您坚持(不建议这样做,但您愿意),则可以为如下类型创建一些检查:

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

But it gets very error prone soon, refactoring will probably be a nightmare etc., but it's your call.. 但是它很快就会变得非常容易出错,重构可能是一场噩梦,等等,但这是您的要求。

Or you maybe can use solution from pwas, but to me it seems unnecessarily complicated for such a basic task. 或者您也许可以使用pwas的解决方案,但是对我来说,对于这样的基本任务而言,它似乎不必要地复杂。 Looks nice and all, but it still returns only the type "object", so it doesn't really solve your specific problem. 看起来不错,但它仍然只返回类型“ object”,因此并不能真正解决您的特定问题。

Also, to address one issue I'm not sure you understand - you've already created the instance, you just return type object. 另外,要解决一个问题,我不确定您是否理解-您已经创建了实例,只需返回type对象。 That is why you can't call any specific methods on this object, because first you have to cast it to something, that actually has that method and make sure the cast can be done (inheritance etc). 这就是为什么您不能在此对象上调用任何特定方法的原因,因为首先您必须将其强制转换为某种实际具有该方法的对象,并确保可以进行强制转换(继承等)。

If interface solution (see other answers) is enough, don't look at this answer. 如果interface解决方案(请参阅其他答案)足够,请不要看此答案。 When you can't use common base class / interface and you still want call members, you can use solution with is keyword (and check types). 当您不能使用通用基类/接口并且仍然需要调用成员时,可以将解决方案与is关键字(以及检查类型)一起使用。 Instead of writing many ifs for each case, you can use fluent API: 您可以使用流利的API,而不是为每种情况编写许多ifs:

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

Solution: 解:

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 - it would be more elegant to use common interface (as other answers say) - my is only alternative way. 记住 -使用通用接口(如其他答案所说)会更优雅-我是唯一的替代方法。

Declare your variable as dynamic 声明变量为动态

dynamic objcls = getconstrorclass();

Using this the will be determined at run-time, whatever the getconstrorclass method returns. 使用此方法,无论getconstrorclass方法返回什么,都将在运行时确定。 You can access any member of the type and you won't get any error at compile-time. 您可以访问该类型的任何成员,并且在编译时不会出现任何错误。 But if you try to access a member which doesn't exists you will get a RuntimeBinderException at runtime. 但是,如果尝试访问一个不存在的成员,则在运行时会收到RuntimeBinderException

I would recommend using an interface and restricting the classes that you can instantiate this way to only those that implement the interface. 我建议使用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不错的示例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM