简体   繁体   English

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

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

I want to create class system to generalize getting and posting data from some data source. 我想创建类系统来概括从某些数据源获取和发布数据。 I have two methods: GetData and PostData. 我有两种方法:GetData和PostData。 Both methods should have some kind of input, and GetData should also have return type. 两种方法都应具有某种输入,GetData也应具有返回类型。 I tried to write generic interface and to implement it in "DatabaseSource" class: 我试图编写通用接口并在“ 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);
} 

Now i tried to implement interface like this: 现在我试图实现这样的接口:

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

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

But i have a problem when I try to instantiate data source like this: 但是当我尝试实例化数据源时,我遇到了一个问题:

IDataSource<InputBase> dataSource = new DatabaseDataSource();

I cannot use DatabaseInput because this code is in some kind of factory method and I should be able to instantiate other IDataSource implementations. 我无法使用DatabaseInput,因为此代码采用某种工厂方法,因此我应该能够实例化其他IDataSource实现。

In short I want to have Input and Output as generic types, and to constraint Input to match concrete IDataSource implementation. 简而言之,我想将Input和Output作为通用类型,并限制Input以匹配具体的IDataSource实现。

If I'm understanding this correctly (and it's admittedly not 100% clear to me), your data source needs to define both the input and the output. 如果我正确理解了这一点(对我来说,这并不是100%清楚的事情),则您的数据源需要同时定义输入输出。 If you do this: 如果您这样做:

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

Then the actual implementation of that method might vary significantly according to what T is. 然后,该方法的实际实现可能会根据T是什么而有很大的不同。 You don't want a scenario of that method where you're inspecting the type of T and branching your code accordingly. 您不希望使用这种方法来检查T的类型并相应地分支代码。

Perhaps what you want is something like this: 也许您想要的是这样的:

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

But even then you've got an interface that's defining two seemingly unrelated operations. 但是即使那样,您仍然具有定义两个看似无关的操作的接口。 (It seems unlikely that TInput can be used both as a query to retrieve data and as a command to post/modify data.) TInput不太可能既可以用作查询检索数据,也可以用作发布/修改数据的命令。)

So perhaps you could break it down further: 因此,也许您可​​以将其进一步分解:

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

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

To instantiate it you could use an abstract factory: 要实例化它,您可以使用抽象工厂:

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

The reason for that is because it avoids the need for your class to call var dataSource = new [whatever]. 这样做的原因是因为它避免了类调用var dataSource = new [whatever]. If you do that then it somewhat defeats the purpose of implementing an interface. 如果这样做,那么它一定会破坏实现接口的目的。 Regardless of what interface you implement, as soon as you explicitly call new and create a specific type, your class is coupled to that type , not the interface. 无论您实现哪种接口,只要您显式调用new并创建特定类型,您的类都将与该类型 (而不是接口)耦合。

That moves the original problem. 这解决了最初的问题。 What is the implementation of the abstract factory? 抽象工厂的实现是什么? The good news is that the class that depends on the factory doesn't care what the implementation of the factory is. 好消息是,依赖于工厂的类并不关心工厂的实现是什么。 But you'll still need one. 但是您仍然需要一个。 One way to go about it is using a DI container. 一种解决方法是使用DI容器。 Windsor is helpful because it provides a pattern for creating abstract factories. 温莎很有用,因为它提供了创建抽象工厂的模式。 This blog post describes how to do that in more detail. 这篇博客文章更详细地描述了如何做到这一点。

Check out Covariance and Contravariance. 查看协方差和相反方差。 https://msdn.microsoft.com/en-us/library/mt654055.aspx https://msdn.microsoft.com/zh-CN/library/mt654055.aspx

You can use the where constraint, click here for more information about constraints. 您可以使用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