簡體   English   中英

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

[英]Return instance using reflection in 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()錯誤,因為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”,因此並不能真正解決您的特定問題。

另外,要解決一個問題,我不確定您是否理解-您已經創建了實例,只需返回type對象。 這就是為什么您不能在此對象上調用任何特定方法的原因,因為首先您必須將其強制轉換為某種實際具有該方法的對象,並確保可以進行強制轉換(繼承等)。

如果interface解決方案(請參閱其他答案)足夠,請不要看此答案。 當您不能使用通用基類/接口並且仍然需要調用成員時,可以將解決方案與is關鍵字(以及檢查類型)一起使用。 您可以使用流利的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();

解:

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

記住 -使用通用接口(如其他答案所說)會更優雅-我是唯一的替代方法。

聲明變量為動態

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不錯的示例

暫無
暫無

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

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