我想创建类系统来概括从某些数据源获取和发布数据。我有两个方法: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实现。
答案 0 :(得分:3)
如果我正确地理解了这一点(并且我无法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容器。温莎很有帮助,因为它提供了创建抽象工厂的模式。 This blog post描述了如何更详细地执行此操作。
答案 1 :(得分:1)
答案 2 :(得分:0)
您可以使用where约束,单击here以获取有关约束的更多信息。
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.