簡體   English   中英

限制C#中泛型的類型參數

[英]Limiting type arguments for generics in C#

我可能會想象事物,但我似乎在Java中回憶起我可以聲明一個字段或參數:

public class BarHandler{

    public Class<? extends Foo> fooType;

    public ProcessedBar Process(string xml){
        Foo foo = fooType.GetInstance();
        return foo.process(xml)
    }
}

這對於工廠樣式系統非常有用,在這種系統中,您必須能夠生成相關類型的新實例。

我試圖弄清楚在C#中是否存在這種模擬,或者如果可能這只是Java中可用的東西。

是的,請參閱通用約束 相當於你的例子是:

public class SomeClass<T>
    where T : Foo
{
    private T fooType;
}

編輯之后的編輯:我相信你指的是通配符 ,在這種情況下你應該閱讀關於泛型的協方差和逆變

public class GenericClass<T> where T : Foo

您可以使用一個非常簡單的包裝器來進行此注釋和便宜的運行時檢查:

public sealed class Type<T>
{
    public Type(Type type)
    {
        if (type == null)
            throw new ArgumentNullException("type");
        if (!typeof(T).IsAssignableFrom(type))
            throw new ArgumentException(string.Format("The specified type must be assignable to '{0}'.", typeof(T).FullName));

        this.Value = type;
    }

    public Type Value
    {
        get;
        private set;
    }
}

使用Activator.CreateInstance實際創建該類型的實例。 假設FooDerived派生自Foo

Type<Foo> fooType = new Type<Foo>(typeof(FooDerived));
Activator.CreateInstance(fooType.Value);

這是280Z28答案的變體。 我已經將“Type”類重命名為“Factory”,因為在我的版本中它公開了GetInstance方法而不是TypeValue屬性。 這使用2個通用參數和通用約束來強制執行Type類的原始答案構造函數中的規則。

public abstract class Factory<T>
{
    public abstract T GetInstance();
}

public sealed class IoCFactory<T, TDerived> : Factory<T>
    where TDerived : T // compiler enforces that TDerived derives from T
{
    public override T GetInstance()
    {
        // TODO: retrieve instance of TDerived from IoC container such as Spring.NET, StructureMap, Unity, etc.
        throw new NotImplementedException();
    }
}

public sealed class ActivatorFactory<T, TDerived> : Factory<T>
    where TDerived : T, new() // compiler enforces that TDerived derives from T and that it has a parameterless constructor
{
    public override T GetInstance()
    {
        return Activator.CreateInstance<TDerived>();
    }
}

public class BarHandler
{
    public Factory<Foo> fooFactory { get; set; }

    public ProcessedBar Process(string xml)
    {
        Foo foo = fooFactory.GetInstance();
        return foo.Process(xml);
    }
}

class Program
{
    static void Main(string[] args)
    {
        BarHandler handler = new BarHandler();

        handler.fooFactory = new ActivatorFactory<Foo, Bar>();

        var processedResult = handler.Process("<bar>Yar!</bar>");
    }
}

暫無
暫無

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

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