C# 按接口返回特定存储库
我有如下代码结构。我目前有两个存储库类,到目前为止,它们都使用单个方法实现了一个通用接口。它们只传递不同的返回类型对象。我还有Factory模式类来检索特定的存储库。我的问题在我的RepositoryFactory中,我收到如下所示的错误消息。老实说,我不知道该怎么办。指望你的支持 错误:C# 按接口返回特定存储库,c#,C#,我有如下代码结构。我目前有两个存储库类,到目前为止,它们都使用单个方法实现了一个通用接口。它们只传递不同的返回类型对象。我还有Factory模式类来检索特定的存储库。我的问题在我的RepositoryFactory中,我收到如下所示的错误消息。老实说,我不知道该怎么办。指望你的支持 错误: public interface IRepository<T> where T :class { IEnumerable<T> GetRecords(); } public
public interface IRepository<T> where T :class
{
IEnumerable<T> GetRecords();
}
public class CsvRepository : IRepository<InputData>
{
private string _path;
public CsvRepository(string path)
{
_path = path;
}
public IEnumerable<IBasic> GetRecords()
{
return from line in File.ReadLines(_path)
select line.Split(',') into parts
where parts.Length == 3
select new InputData { Name = parts[0], X = Convert.ToInt32(parts[1]), Y = Convert.ToInt32(parts[2]) };
}
}
//other repositories:
public class OracleRepository : IRepository<OtherDataType>
{
..
}
...
//Factory pattern to get specific repository on demand
//Implement IoC later on (register instead of cases)
public class RepositoryFactory
{
public static IRepository GetRepository(DataSource repositoryType)
{
IRepository repo;
switch (repositoryType)
{
//break;
case DataSource.Csv:
repo = new CsvRepository("path"); //perhaps path shoudln't br right passed right here - so where?
break;
case DataSource.Oracle:
repo = new OracleRepository();
break;
default:
throw new ArgumentException("Invalid Repository Type");
}
return repo;
}
}
代码:
public interface IRepository<T> where T :class
{
IEnumerable<T> GetRecords();
}
public class CsvRepository : IRepository<InputData>
{
private string _path;
public CsvRepository(string path)
{
_path = path;
}
public IEnumerable<IBasic> GetRecords()
{
return from line in File.ReadLines(_path)
select line.Split(',') into parts
where parts.Length == 3
select new InputData { Name = parts[0], X = Convert.ToInt32(parts[1]), Y = Convert.ToInt32(parts[2]) };
}
}
//other repositories:
public class OracleRepository : IRepository<OtherDataType>
{
..
}
...
//Factory pattern to get specific repository on demand
//Implement IoC later on (register instead of cases)
public class RepositoryFactory
{
public static IRepository GetRepository(DataSource repositoryType)
{
IRepository repo;
switch (repositoryType)
{
//break;
case DataSource.Csv:
repo = new CsvRepository("path"); //perhaps path shoudln't br right passed right here - so where?
break;
case DataSource.Oracle:
repo = new OracleRepository();
break;
default:
throw new ArgumentException("Invalid Repository Type");
}
return repo;
}
}
因此:
然而,我得到了错误:
Cannot implicitly convert type 'CsvRepository' to 'IRepo'. An explicit conversion exists (are you missing a cast?)
Cannot implicitly convert type 'SqlRepository' to 'IRepo'. An explicit conversion exists (are you missing a cast?)
您可以为您的数据再添加一个抽象级别,以便在泛型中使用新的抽象:
public interface IBasic { }
public class InputData : IBasic { }
public class OtherDataType : IBasic { }
现在,您的IRepository应该针对IBasic接口编写
public interface IRepository<T> where T : IBasic
{
IEnumerable<T> GetRecords();
}
公共接口假定,其中T:IBasic
{
IEnumerable GetRecords();
}
现在,您可以具体实现上述假设:
public class CsvRepository : IRepository<IBasic>
{
private string _path;
public CsvRepository()
{
var filename = ConfigurationManager.AppSettings["CSVFileName"];
_path = AppDomain.CurrentDomain.BaseDirectory + filename;
}
public IEnumerable<IBasic> GetRecords()
{
_path = "Read path";
//Implement Yield & iterator here !!
throw new NotImplementedException();
}
}
//other repositories:
public class OracleRepository : IRepository<IBasic>
{
private string _path;
public OracleRepository()
{
var filename = ConfigurationManager.AppSettings["CSVFileName"];
_path = AppDomain.CurrentDomain.BaseDirectory + filename;
}
public IEnumerable<IBasic> GetRecords()
{
_path = "Read path";
//Implement Yield & iterator here !!
throw new NotImplementedException();
}
}
公共类CsvRepository:IRepository
{
私有字符串路径;
公共CsvRepository()
{
var filename=ConfigurationManager.AppSettings[“CSVFileName”];
_路径=AppDomain.CurrentDomain.BaseDirectory+文件名;
}
公共IEnumerable GetRecords()
{
_path=“读取路径”;
//在这里实现Yield和iterator!!
抛出新的NotImplementedException();
}
}
//其他存储库:
公共类OracleRepository:IRepository
{
私有字符串路径;
公共或公共场所
{
var filename=ConfigurationManager.AppSettings[“CSVFileName”];
_路径=AppDomain.CurrentDomain.BaseDirectory+文件名;
}
公共IEnumerable GetRecords()
{
_path=“读取路径”;
//在这里实现Yield和iterator!!
抛出新的NotImplementedException();
}
}
现在,您的工厂看起来是这样的:
public class RepositoryFactory
{
public static IRepository<IBasic> GetRepository(DataSource repositoryType)
{
IRepository<IBasic> repo = null;
switch (repositoryType)
{
//break;
case DataSource.Csv:
repo = new CsvRepository();
break;
case DataSource.Oracle:
repo = new OracleRepository();
break;
default:
throw new ArgumentException("Invalid Repository Type");
}
return repo;
}
}
公共类存储工厂
{
公共静态IRepository GetRepository(DataSource repositoryType)
{
i预期回购=空;
开关(repositoryType)
{
//中断;
案例数据源.Csv:
回购=新的CsvRepository();
打破
案例数据源。Oracle:
回购=新的OracleRepository();
打破
违约:
抛出新ArgumentException(“无效存储库类型”);
}
回购回报;
}
}
我相信您的目标是拥有一个存储库,但要有多个实现。然后您要选择其中一个实现
public interface IRecordRetrieverRepository<out TModel> : IDisposable
{
IEnumerable<TModel> RetrieveAllRecords();
}
我们已经定义了我们的工厂接口
public class RecordRetrieverFactory<TContext, TModel> : IRecordRetrieverFactory
{
public TRecordRetrieverRepository BuildContext() => new TContext<TModel>();
}
公共类RecordRetrieverFactory:IRecordRetrieverFactory
{
public TRecordRetrieverRepository BuildContext()=>new TContext();
}
然后您可以简单地执行以下语法
using(var context = new RecordRetrieverFactory<ExcelContext, SampleModel>().BuildContext())
return context.RetrieveAllRecords();
使用(var context=new RecordRetrieverFactory().BuildContext())
返回context.RetrieveAllRecords();
在不丢失表达代码的情况下提供了一点灵活性。我没有验证或测试代码,写得很快,但应该可以工作。不过,有些反射可能被忽略了。
IRepository
是一种通用类型。如果不指定泛型类型,就不能声明它。@BJMyers-ye我知道,但是这个接口用于不同的存储库。我应该创建特殊的非T-generic接口并在所有存储库中实现,以便能够在Factory模式方法中使用我的存储库,还是有更合适的方法?或者其他方法,如IRepository-->IRepository:IRepository和在工厂中使用IRepository方法?不确定。@BJMyers查看了我在编辑子句中的主要帖子,我到目前为止一直在尝试什么。@最后一个帖子:您认为如何将路径传递到CsvRepository的ctor中-目前我在GetRepository方法中有它,但我认为这不是一个好方法,应该在哪里传递它呢?其他信息也会传递到其他存储库。在当前的解决方案中,对象是在GetRepository方法中创建的,所以这意味着在ctorts中,所有这些都将存在——请给出建议,因为我不认为getfactory不适合这样做。顺便说一下,我还需要通过GetRepository参数传递这些信息。。。不好看起来很好,让我先检查一下(不会忘记马克作为答案)。顺便问一下,你能告诉我另外一件事吗,为什么我试着从我的主要帖子的编辑部分给出提到的错误?如果你能提供额外的答案,我将不胜感激。谢谢@JimmyJimm:我看不出你的抽象有任何问题。我添加了更多的代码,我想这足以说明为什么我会出现下面这一错误:repo=new CsvRepository();repo=newsqlrepository();(请注意,我谈论的是我的编辑主博文部分代码。如果在OracleRepository函数public IEnumerable GetRecords()中,我想实现Yield…只要函数不知道要定义为return的确切类型,如何实现它?查看新内容:从File.ReadLines(_settings.Path)中的行返回)选择line.Split(',')到parts.Length==3的部分,选择new InputData{X=Convert.ToInt32(parts[1]),Y=Convert.ToInt32(parts[2]);但InputData应该是IBasic,然后无法正确设置ctor参数。。。
public class ExcelContext<TModel> : IRecordRetrieverRepository<TModel>
{
public IEnumerable<TModel> RetrieveAllRecords()
{
// Actual implementation.
}
}
public interface IRecordRetrieverFactory
{
TRecordRetrieverRepository BuildContext();
}
public class RecordRetrieverFactory<TContext, TModel> : IRecordRetrieverFactory
{
public TRecordRetrieverRepository BuildContext() => new TContext<TModel>();
}
using(var context = new RecordRetrieverFactory<ExcelContext, SampleModel>().BuildContext())
return context.RetrieveAllRecords();