如何在 C# 中使用泛型 return 接口

How to return interface using generic in C#

我是 C# 泛型概念的新手,我想 return 使用泛型概念实现的接口 class。下面是我的例子,目前没有泛型实现:

1) Factory Class which return interface 和 this class 有两个重载方法接受不同的数据模型:

public class Factory
{
    public ICommon Init(DBInfoData dbInfoData)
    {
        return new ClassA(dbInfoData);
    }

    public ICommon Init(WebInfoData webInfoData)
    {
        return new ClassB(webInfoData);
    }
}

2)接口和接口实现了两个class如下:

//=== Common Interface
public interface ICommon
{
    void MethodA();
    void MethodB();
}

//=== Internal access only ClassA
internal class ClassA : ICommon
{
    private DBInfoData _DBInfoData = null;
    public ClassA(DBInfoData dbInfoData)
    {
        _DBInfoData = dbInfoData;
    }

    public void MethodA()
    {
        throw new NotImplementedException();
    }

    public void MethodB()
    {
        throw new NotImplementedException();
    }
}

//=== Internal access only ClassB
internal class ClassB : ICommon
{
    private WebInfoData _WebInfoData = null;

    public ClassB(WebInfoData webInfoData)
    {
        _WebInfoData = webInfoData;
    }

    public void MethodA()
    {
        throw new NotImplementedException();
    }

    public void MethodB()
    {
        throw new NotImplementedException();
    }
}

3) 数据模型 class 如下:

//=== Database Information
public class DBInfoData
{
    public string Server { get; set; }
    public string Database { get; set; }
}

//=== Web Server Information
public class WebInfoData
{
    public string URL { get; set; }
    public int Port { get; set; }
}

现在我想在工厂中实现 C# 的通用功能 class 我不想声明两个重载方法。使用单一方法,我可以 return ClassA 或 ClassB 基于数据模型传递。

您可以编辑 Init 方法,而无需编辑任何其他内容。此方法将采用泛型类型参数 T,它可以是任何类型。然后你可以使用is运算符,它根据docs用来进行类型测试。但是,您需要检查任何不受支持的 T 类型,因为您没有向传递的泛型类型添加任何约束。原始实现将是:

public class Factory
{
    public ICommon Init<T>(T infoData)
    {
        if (infoData is DBInfoData dbInfoData) {
            return new ClassA(dbInfoData);
        }
        if (infoData is WebInfoData webInfoData) {
            return new ClassB(webInfoData);
        }

        throw new Exception($"Cannot create instance for info data of type {infoData.GetType().Name}");
    }
}

并对其进行测试:

    var factory = new Factory();

    var t1 = factory.Init(new DBInfoData()); // will be ClassA
    var t2 = factory.Init(new WebInfoData()); // ClassB

为了使它更复杂,您可以通过引入空接口 IInfoData 来为 类 DBInfoDataWebInfoData 引入 type constraint on your generic T class to make sure you can only pass appropriate types. For the current situation, you could create a marker interface。那么你必须像这样继承你的类:

public interface IInfoData {}

public class DBInfoData : IInfoData
{
    public string Server { get; set; }
    public string Database { get; set; }
}

public class WebInfoData : IInfoData
{
    public string URL { get; set; }
    public int Port { get; set; }
}

现在两者都继承自(实际上 'marked by')您的基本接口。通过添加我在上面链接的文档中显示的约束,向您的工厂引入约束以仅允许 IInfoData 的后代作为参数传递(因此 DBInfoDataWebInfoData):

public class Factory
{
    public ICommon Init<T>(T infoData) where T: IInfoData
    {
        if (infoData is DBInfoData dbInfoData) {
            return new ClassA(dbInfoData);
        }
        if (infoData is WebInfoData webInfoData) {
            return new ClassB(webInfoData);
        }

        throw new Exception($"Cannot create instance for info data of type {infoData.GetType().Name}");
    }
}

IInfoData 的后代之外的任何类型都会导致编译错误,您就完成了。像我之前的例子一样使用它:

    var factory = new Factory();

    var t1 = factory.Init(new DBInfoData()); // will be ClassA
    var t2 = factory.Init(new WebInfoData()); // ClassB