簡體   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