【问题标题】:C# - change "where" restriction through inheritanceC# - 通过继承改变“where”限制
【发布时间】:2012-07-10 09:51:39
【问题描述】:

假设我有一个通用数据访问层,它应该支持不同的实现。为了实现这一点,我有一个基本接口IPeristenceService,它定义了访问持久层内数据的所有方法。界面可能如下所示:

public interface IPersistence
{
    TData GetData<TData, TKey>(TKey Key);
}

因此持久化服务无法创建仅由其接口定义的对象实例,因此限制GetData-方法的实现是一个不错的决定:

public interface IPersistence
{
    TData GetData<TData, TKey>(TKey Key) where TData : class, new();
}

这非常简单,因为实现此接口的开发人员在尝试返回接口指针时将无法编译他们的代码。持久层内部的数据需要用实现的对象来表示,而不是接口!

现在假设我们正在创建一个持久化服务,它将数据持久化到一个关系数据库中,由实体表示。所有实体都继承自一个基本接口:IEntity。传递非实体对象一定会失败,因为持久化服务只能持久化实体。所以我们需要验证传递的对象实例是否继承自IEntity。在编译时使用 where-notation 是可能的,但只需实现这样的接口:

public class DbPersistence : IPersistence
{
    public TData IPersistence.GetData<TData, TKey>(TKey Key)
        where TData : IEntity, class, new();
    {
        // fancy data access code
    }
}

不起作用,是吗?!

有什么方法可以实现我想要做什么?

提前谢谢你:-)

【问题讨论】:

  • 如果您可以将其设为运行时错误,您可以检查 Tdata 是否“是”IEntity。附带说明一下,利用现有的持久性框架(例如 NHibernate)不是更简单(不是专家,只是听说过它,听起来它会解决与您的代码相同的问题)吗?
  • 是的,运行时验证是我目前解决这个问题的方法,但它们对于开发人员来说非常不直观且容易出错,因为他们需要调试应用程序。

标签: c# oop inheritance generic-constraints


【解决方案1】:

TData 上的类型约束继承自您正在实现的接口方法,这就是为什么无法在实现中修改它们的原因。我能想到的典型解决方案有两种:

IEntity 约束向上移动到接口定义

public interface IPersistence
{
    TData GetData<TData, TKey>(TKey Key) where TData : class, IEntity, new();
}

这在很多情况下都是合适的,因为所有持久化对象之间有一定数量的共同点既合理又合乎需要。

显式实现原始接口并公开实现专用接口

public interface IPersistence
{
    TData GetData<TData, TKey>(TKey Key) where TData : class, new();
}

public interface IDbPersistence
{
    TData GetData<TData, TKey>(TKey Key) where TData : class, IEntity, new();
}

public class DbPersistence : IPersistence, IDbPersistence
{
    TData IPersistence.GetData<TData, TKey>(TKey Key)
    {
        // fancy data access code
    }

    TData GetData<TData, TKey>(TKey Key)
    {
        return ((IPersistence)this).GetData<TData, TKey>(Key);
    }
}

通过这种方式,您可以将自定义持久层用作更丰富的 IDbPersistence,同时保持与数据访问层中只知道 IPersistence 的部分的兼容性。

【讨论】:

  • 谢谢! :) 将 IEntity 移动到接口定义并不是我想要做的,因为在某些用例中数据不会被保存为实体(例如,它们可以从云应用程序中读取,...)。使用不同的接口定义正是我想要的! :)
猜你喜欢
  • 1970-01-01
  • 2011-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多