繁体   English   中英

通用接口实现:通用返回类型和通用输入类型

[英]Generic interface implementation: Generic return type and generic input type

我想创建类系统来概括从某些数据源获取和发布数据。 我有两种方法:GetData和PostData。 两种方法都应具有某种输入,GetData也应具有返回类型。 我试图编写通用接口并在“ DatabaseSource”类中实现它:

public class QueryParameter
{
    public QueryParameter()
    {
        this.Direction = ParameterDirection.Input;
    }

    public string Name { get; set; }
    public object Value { get; set; }
    public ParameterDirection Direction { get; set; }
}

public class InputBase
{
    public InputBase()
    {
        ResultMapping = new Dictionary<string, string>();
        Parameters = new List<QueryParameter>();
    }
    public Dictionary<string, string> ResultMapping { get; set; }
    public List<QueryParameter> Parameters { get; set; }
}
public class DatabaseInput: InputBase
    {
        public string Query { get; set; }
        public DatabaseCommandType CommandType { get; set; }
    }

public interface IDataSource<I> where I: InputBase
{
    IEnumerable<T> GetData<T>(I input);
    void PostData(I Input);
} 

现在我试图实现这样的接口:

public class DatabaseDataSource: IDataSource<DatabaseInput>
{
    public IEnumerable<T> GetData<T>(DatabaseInput Input)
    {
        //implementation
    }

    public void PostData(DatabaseInput Input)
    {
        //implementation
    }
}

但是当我尝试实例化数据源时,我遇到了一个问题:

IDataSource<InputBase> dataSource = new DatabaseDataSource();

我无法使用DatabaseInput,因为此代码采用某种工厂方法,因此我应该能够实例化其他IDataSource实现。

简而言之,我想将Input和Output作为通用类型,并限制Input以匹配具体的IDataSource实现。

如果我正确理解了这一点(对我来说,这并不是100%清楚的事情),则您的数据源需要同时定义输入输出。 如果您这样做:

public IEnumerable<T> GetData<T>(DatabaseInput Input)

然后,该方法的实际实现可能会根据T是什么而有很大的不同。 您不希望使用这种方法来检查T的类型并相应地分支代码。

也许您想要的是这样的:

public interface IDataSource<TInput, TOutput> where TInput: InputBase
{
    IEnumerable<TOutput> GetData(TOutput input);
    void PostData(TInput Input);
} 

但是即使那样,您仍然具有定义两个看似无关的操作的接口。 TInput不太可能既可以用作查询检索数据,也可以用作发布/修改数据的命令。)

因此,也许您可​​以将其进一步分解:

public interface IDataSource<TInput, TOutput> where TInput: InputBase
{
    IEnumerable<TOutput> GetData(TOutput input);
}

public interface IDataCommand<TInput> where TInput:InputBase
{
    void PostData(TInput Input);
}

要实例化它,您可以使用抽象工厂:

public interface IDataSourceFactory<TInput, TOutput>
{
    IDataSource<TInput, TOutput> Create();
    void Release(IDataSource<TInput, TOutput> created);
}

这样做的原因是因为它避免了类调用var dataSource = new [whatever]. 如果这样做,那么它一定会破坏实现接口的目的。 无论您实现哪种接口,只要您显式调用new并创建特定类型,您的类都将与该类型 (而不是接口)耦合。

这解决了最初的问题。 抽象工厂的实现是什么? 好消息是,依赖于工厂的类并不关心工厂的实现是什么。 但是您仍然需要一个。 一种解决方法是使用DI容器。 温莎很有用,因为它提供了创建抽象工厂的模式。 这篇博客文章更详细地描述了如何做到这一点。

查看协方差和相反方差。 https://msdn.microsoft.com/zh-CN/library/mt654055.aspx

您可以使用where约束,请单击此处以获取有关约束的更多信息。

where T : class //The type argument must be a reference type; this applies also to any class, interface, delegate, or array type.

where T : <interface name> //The type argument must be or implement the specified interface. Multiple interface constraints can be specified. The constraining interface can also be generic.

暂无
暂无

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

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