簡體   English   中英

C#中的參數化System.Type變量

[英]Parameterized System.Type Variable in C#

我正在嘗試在C#中創建一個工廠類,該工廠類返回的對象是或擴展了某種基本類型。 每當我在工廠調用getInstance() ,我都需要實例化此類型的新實例,因此我真的只想接受並存儲該類型本身。 在Java中,我使用了Class<? extends Base> Class<? extends Base>來保存要創建的類,然后在其上調用getInstance()

我了解如何在C#中使用Activator類從System.Type創建新對象,但是我不確定的部分是對類類型的約束。 我希望只能接受屬於或擴展基類的Type。 我意識到我可以在工廠中將設置器更改為接受基本類型的實際對象,然后從中檢索類型,但是我並不是真的想實例化整個對象只是為了檢索Type變量。

下面是一個小的Java程序示例,目的是演示我的需求,以防我的問題不清楚。 在C#中有什么方法可以做到這一點?

class Program {
   public static void main(String[] args) throws InstantiationException, IllegalAccessException {
         Factory.setClass(Base.class);
         Base b = Factory.getInstance();
         b.Print();

         Factory.setClass(Child.class);
         b = Factory.getInstance();
         b.Print();
      }
}

class Factory {
   private static Class<? extends Base> type;

   // What I want to do in C#.
   public static void setClass(Class<? extends Base> newType) {
      type = newType;
   }

   // What I don't want to have to do in C#.
   public static void setClassFromObject(Base newTypeObject) {
      type = newTypeObject.getClass();
   }

   public static Base getInstance() throws InstantiationException, IllegalAccessException {
      return type.newInstance();
   }
}

class Base {
   public void Print() {
      System.out.println("Hello from base.");
   }
}

class Child extends Base {
   @Override
   public void Print() {
      System.out.println("Hello from child.");
   }
}

我看不到如何在編譯時強制執行此操作,但是如果您可以通過運行時檢查確定,則可以這樣做:

class Factory 
{
    private static Type _type;

    public static void SetClass(Type t) 
    {
        if (!(typeof(Base)).IsAssignableFrom(t))
        {
            throw new ArgumentException("type does not extend Base", nameof(t));
        }

        _type = t;
    }

    public static Base GetInstance() 
    {
        return (Base)Activator.CreateInstance(_type);
    }
}

您可以使“ GetInstance”方法動態化,以便在設置類時也可以設置該方法。 這樣,您可以在運行時依賴泛型來獲取正確的類型。 它可能看起來像這樣:

public class Factory
{
    private static Func<Base> _getInstance;

    //option if you want to pass in an instantiated value
    public static void SetClass<T>(T newType) where T : Base, new()
    {
        _getInstance = () => new T();
    }

    //option if you just want to give it a type
    public static void SetClass<T>() where T : Base, new()
    {
        _getInstance = () => new T();
    }

    public static Base GetInstance()
    {
        return _getInstance();
    }

    //you could just make GetInstance Generic as well, so you don't have to set the class first
    public static Base GetInstance<T>() where T : Base, new()
    {
        return new T();
    }
}

暫無
暫無

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

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