基于类型调用 DAL 方法

Posted

技术标签:

【中文标题】基于类型调用 DAL 方法【英文标题】:Call DAL Method Based on Type 【发布时间】:2012-04-20 13:48:38 【问题描述】:

我正在开发一个应用程序,我需要根据调用类的泛型类型调用两种数据方法之一。例如,如果 T 是 Foo 类型,我将调用 data.GetFoo():

private static List<T> GetObjectList(DateTime mostRecentProcessedReadTime)

    using (MesReportingDal data = new MesReportingDal())
    
        return data.GetFoo(mostRecentProcessedReadTime);  // Notice GetFoo()
    

如果 T 是 Bar 类型,我会调用 data.GetBar():

private static List<T> GetObjectList(DateTime mostRecentProcessedReadTime)

    using (MesReportingDal data = new MesReportingDal())
    
        return data.GetBar(mostRecentProcessedReadTime);  // Notice GetBar()
    

在此之前,我只需要一个 DAL 方法,因为所有类型的检索方式都相同。我现在需要调用两种方法之一,具体取决于 T 的类型。

我试图避免这样的事情:

private static List<T> GetObjectList(DateTime mostRecentProcessedReadTime)

    using (MesReportingDal data = new MesReportingDal())
    
        if (T is Foo)  return data.GetFoo(mostRecentProcessedReadTime); 
        if (T is Bar)  return data.GetBar(mostRecentProcessedReadTime); 
    

这违反了 OCP。有没有一种优雅的方式来处理这个问题,所以我可以摆脱我的 if 语句?

编辑 - 这就是类型的样子

public partial class Foo1 : IDataEntity  
public partial class Foo2 : IDataEntity  
public partial class Bar1 : IDataEntity  
public partial class Bar2 : IDataEntity  

这些 Foos 和 Bars 是用于 Linq-to-SQL 的 DBML 项。

【问题讨论】:

您是否可以控制“T”类 - 它们是否可以更改,您是否有基本接口/类等。 如果您不想更改 Foo*、Bar* 并且它必须是 GetFoo、GetBar - 而不是 ataddeini 建议的 Get()(如果我理解正确?)。您打算如何“调用”GetObjectList()?你在定义例如Foo, Bar 在调用之前(所以你有一个类型的变量) - 或者你想以某种高度通用的方式调用它(使用另一个通用方法中的 T )?如果可以的话,最简单的是 ataddeini 所说的。 static 的使用已经让我很担心了。你能解释一下你认为这违反了OCP吗?没有上下文,很难说。 @NSGaga 我也许可以按照 ataddeini 所说的去做。我还没有时间。我很快就会检查出来。 @jeyoung 它违反了OCP,因为我们必须记住if语句并为每个新类型添加它。 【参考方案1】:

我会将GetFooGetBar 更改为Get,并将MesReportingDal 也设为通用。

所以我认为你最终会得到这样的结果:

private static List<T> GetObjectList(DateTime mostRecentProcessedReadTime)

    using (var data = new MesReportingDal<T>())
    
        return data.Get(mostRecentProcessedReadTime);        
    

顺便说一句,拥有using 语句还需要MesReportingDal 实现IDisposable,否则会出现以下编译错误:

'MesReportingDal':在 using 语句中使用的类型必须隐式转换为 'System.IDisposable'

更新

因此,在考虑了更多并阅读了您的反馈之后,您可以选择提取存储库接口并将创建推回工厂方法。这将允许您维护单个 data.Get(...) 调用,但使用基于 T 的不同实现

public interface IRepository<T> : IDisposable

    IList<T> Get(DateTime mostRecentRead);


public class FooRepo : IRepository<Foo>

    public IList<Foo> Get(DateTime mostRecentRead)
    
        // Foo Implementation
    


public class BarRepo : IRepository<Bar>

    public IList<Bar> Get(DateTime mostRecentRead)
    
        // Bar Implemenation
    

你的工厂可能看起来像这样

public class RepositoryFactory

    public static IRepository<T> CreateRepository<T>()
    
        IRepository<T> repo = null;
        Type forType = typeof(T);

        if (forType == typeof(Foo))
        
            repo = new FooRepo() as IRepository<T>;
        
        else if (forType == typeof(Bar))
        
            repo = new BarRepo() as IRepository<T>;
        

        return repo;
    

这将使您保持初始代码块干净

private static IList<T> GetObjectList(DateTime mostRecentProcessedReadTime)

    using (var data = RepositoryFactory.CreateRepository<T>())
    
        return data.Get(mostRecentProcessedReadTime);
    

希望对您有所帮助。

【讨论】:

我不知道这会起作用,可能是因为我不是很清楚。 data.Get() 方法根据类型有不同的实现。 Get() 中的算法不同。 @BobHorn 对,好的。考虑更多这一点,我不断回到存储库接口和工厂。我会尽快用一个例子来更新。 谢谢。虽然这将 if 逻辑推到了其他地方,但它确实使消费代码保持干净。我希望完全避免 if 逻辑,但这个解决方案至少将其保留在工厂内。我认为我唯一的其他选择是反射,但这现在可以工作。 仅供参考,此行最终返回 null:repo = new FooRepo() as IRepository;我不需要解决它,但我至少想让你知道。

以上是关于基于类型调用 DAL 方法的主要内容,如果未能解决你的问题,请参考以下文章

后台三层Dal层调用存储过程

我应该在哪里使用 C# 调用方法 connection.Open()?

返回强类型存储过程结果

学生管理系统

在 DAL 中处理数据库连接的最佳方法 - 创建还是通过?

类型初始值设定项引发异常