【问题标题】:What is a better way to check Enum and call repository methods检查枚举和调用存储库方法的更好方法是什么
【发布时间】:2018-07-04 12:44:30
【问题描述】:

我有一个存储库,可以获取不同类型的 IEnumerable

我可以通过使用来做到这一点:

switch (returnType)
{
    case ReturnType.HR:
        _repo.GetSystemManuals();
        break;
    case ReturnType.Finance:
        _repo.GetPrivateRecords();
        break;
    case ReturnType.Dev:
        _repo.GetTimeLine();
        break;
    case ReturnType.Admin:
        _repo.GetLedger();
        break;
    case ReturnType.Support:
        _repo.GetRoster();
        break;
}

但这违反了SOLID的开/关原则。

我想到的一种方法是创建一个字典,

private static readonly IDictionary<S95Type, IQueryable<Customer>> ReqTypeMapper 
      = new Dictionary<S95Type, IQueryable<HR>>();
ReqTypeMapper.Add(ReturnType.HR, _repo.GetHR()());

但不确定如何执行具有不同返回类型的不同方法..

【问题讨论】:

  • Open/Close 与 switch 语句无关。没有扩展,没有对类型的修改。另一方面,repository 并不是数据层的不同名称。它应该处理一个 single 实体,而不是很多。
  • @PanagiotisKanavos,如果我将来有不同的类型,我将不得不在我当前的课程中进行修改。只是想了解是否有更好的方法。
  • 您没有存储库,您正在尝试创建工厂或 DI 容器。回购应该与单个实体一起处理。如果您想将不同的 repos 传递给不同的客户端,让他们接受 IRepository&lt;T&gt; 并使用 DI 容器来生成适当的实例
  • repo 的类型是什么?
  • @Simons 换句话说,IOfficeRepository 打破了单一职责原则,试图成为每个人的仓库

标签: c# .net enums solid-principles


【解决方案1】:

您不需要大开关。

只需动态地调用该方法。

_repo.getType().GetMethod("Get" + ((ReturnType)returnType).ToString()).Invoke(null,null)

【讨论】:

  • 嘿,可能不好,虽然枚举类型名称与方法名称不匹配..确实编辑了问题..
  • 你也不需要反射 - 使用泛型和方法重载可以在不牺牲类型安全的情况下执行相同的操作
【解决方案2】:

添加简单的情况,您可以在 enum 类型和 Dictionary 中的 method 本身之间进行转换。

//Define type
public enum ReturnType {
    HR,
    Dev,
    Finance
}

//Define methods
public void HRMethod() { Console.WriteLine("HR"); }
public void DevMethod() { Console.WriteLine("Dev"); }
public void FinanceMethod() { Console.WriteLine("Finance"); }

//Create a dictionary, where You add particular method for particular type
Dictionary<ReturnType, Action> myDict = new Dictionary<ReturnType, Action>();
myDict.Add(ReturnType.HR, HRMethod);
myDict.Add(ReturnType.Dev, DevMethod);
myDict.Add(ReturnType.Finance, FinanceMethod);

//Whenever the call occurs
myDict[ReturnType.HR].Invoke(); 
> HR

编辑:

返回类型为 IEnumerable 时,它​​看起来像这样:

//Define methods
public IEnumerable<HR> GetHR() { return new List<HR>() {new HR() {Name="HR" } }; }
public IEnumerable<Dev> GetDev() { return new List<Dev>() {new Dev() {Name="Dev" } }; }

//Create dict + fill
Dictionary<ReturnType, Func<object>> myDict2 = new Dictionary<ReturnType, Func<object>>();
myDict2.Add(ReturnType.HR, GetHR);
myDict2.Add(ReturnType.Dev, GetDev);

//Work with it as with result type
var lRes = (myDict2[ReturnType.HR].Invoke() as IEnumerable<HR>);
Console.WriteLine(lRes.First().Name);
> HR

解决方案 2:

有点复杂的方法是:创建自定义attribute,在每个枚举值上设置attribute 与要调用的方法的值(或方法的名称,见下文)。一旦你有了这个,在开始时反射你将阅读这些属性,创建DictionaryService,这将提供所需的方法。

无法使用委托创建自己的属性(截至:Is it possible to have a delegate as attribute parameter?)。所以你必须使用“hacky”解决方案,包括原始类的类型,然后是方法名称。

【讨论】:

  • 您的解决方案 1 仍然无法工作 - 当您可以硬编码例如 HR 作为枚举并返回但如果您有一个变量 returnType 就像 OP 一样,那么它就无法工作。演示:rextester.com/BAE41261
  • 是 myDict2.Add(ReturnType.HR, GetHR);是有效的陈述吗?不应该是 myDict2.Add(ReturnType.HR, ()>{return GetHR();}); 吗?
  • @Simsons 您的语法包括 Lamba 语法,您可以省略。 stackoverflow.com/questions/12267280/…
  • @Jamiec 这段代码的重点是展示如何将Enum 中的值和方法名称压缩在一起。转到具体示例(如您所描述的),它没有在其他地方编写,抽象和参数化必须无处不在。进一步说,在某些时候你需要到达底层并说 -> this is the code that does the job
  • 没有代码可以完成这项工作 - 你不能在这里使用泛型 - 解决方案(正如其他人指出的那样)是注入一个在正确的地方只做一件事的 repo,没有多用途回购,然后尝试使用返回不同值的方法字典对其进行泛化。以你描述的任何一种方式都是不可能的。
【解决方案3】:

我认为您应该重新考虑您的设计并为每种类型创建一个存储库。 根据定义,存储库不应处理许多不同的实体。 这将是一个干净且可维护的解决方案。

【讨论】:

  • 当然应该,仅存在于另一个实体(聚合)上下文中的实体永远不应该拥有自己的存储库。拥有一个管理它们的存储库会在一个地方对它们实施约束 - 聚合的存储库。如果您开始为每个实体创建存储库,您就会通过添加更多可能导致数据一致性丢失的方式来为错误留出余地。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-07
  • 1970-01-01
  • 2017-02-01
  • 1970-01-01
相关资源
最近更新 更多