【问题标题】:Confusion with multiple interface implementation与多接口实现混淆
【发布时间】:2011-09-15 01:11:34
【问题描述】:

我有以下一组接口和类。

public interface IValidatableObject
{
   List<string> ValidationErrors { get; }
   bool Validate();
}

public class ValidatableObject : IValidatableObject
{
   public List<string>ValidationErrors { get; }
   public bool Validate()
   {
      //dostuff
   }
}

public interface IDeviceDataObject
{
   int Id { get; set; }
   string Name { get; set; }
}

public class DeviceDataObject : ValidatableObject, IDeviceDataObject
{
   public int Id { get; set; }
   public string Name { get; set; }
}

public class DeviceService
{
   public bool ValidateDevice(IDeviceDataObject device)
   {
       return device.Validate(); // This throws a compiler error
   }
}

上面的服务操作ValidateDevice的问题是编译器无法解析device.Validate(),因为IDeviceDataObject没有实现IValidatableObject接口。

我的问题是,将IValidatableObject 更改为实现IValidatableObject 是否正确。我有点不确定这是否是一种好的做法,因为在我看来,DeviceDataObject 是两次实施IValidatableObject - 一次是通过ValidatableObject,一次是通过IDeviceDataObject。谁能帮我解决这个问题?

public interface IDeviceDataObject : IValidatableObject
{
   int Id { get; set; }
   string Name { get; set; }
}

【问题讨论】:

  • 为什么您的 ValidateDevice 签名看起来不像 public bool ValidateDevice(IValidatableObject someobj)?这不是表达验证方法的功能吗:它需要可验证的东西。其他一切都可以保持原样。
  • 公平通话。但是,如果它是一个 CreateDevice 方法,它需要知道它是一个传入的 IDeviceDataObject 但它仍然需要具有 IValidatableObject 功能?
  • 所以 - 因为我不知道这里的大局 - 所有 IDeviceDataObjects 都应该是可验证的吗?如果是,让IDeviceDataObject 继承自IValidatableObject。如果不是,那么这不是解决方案。有时真的很简单:这只是语义上有意义的问题。然后将其依次转换为代码是一个相当简单的步骤。

标签: c# oop inheritance interface refactoring


【解决方案1】:

我可能在这里理解了一些错误(而且我不了解您的整个类架构),但是为什么您的 ValidateDevice 方法不只采用可验证的对象?签名看起来像:

public bool ValidateDevice(IValidatableObject someobj)

这不是表达了验证方法的功能吗:它需要可验证的东西。其他一切都可以保持原样(即不要让IDeviceDataObject 继承自IValidatableObject,因为您可能想表达并非每个设备数据对象也是可验证的)

第二种方法,如果你想确保ValidateDevice 只接受实现IDeviceDataObject 的对象,你也可以尝试交叉转换为IValidatableObject

public bool ValidateDevice(IDeviceDataObject someobj)
{
    if(someobj is IValidatableObject)
    {
        return ((IValidatableObject)device).Validate();
    }
    return //something that makes sense if the device is not validatable
}

【讨论】:

    【解决方案2】:

    您可以简单地转换为 IValidatableObject。

    public class DeviceService 
    { 
       public bool ValidateDevice(IDeviceDataObject device) 
       { 
           IValidatableObject v = device as IValidatableObject;
    
           if (v != null)
               return device.Validate();
           return false;
       } 
    } 
    

    【讨论】:

    • 但是所有处于有效状态但没有实现IValidatableObject的设备都会验证失败。
    • @Eranga - 还有?他们可以通知有效的唯一方法是实现 IValidatableObject。我没有看到问题。
    • API 在撒谎。我希望ValidateDevice 方法基于IDeviceDataObject 合同进行验证。我必须通过ValidateDevice 的实现知道我还必须实现IValidatableObject
    • @Eranga - 不,API 没有说谎。如果对象未实现 IValidatableObject,则无法验证该对象。就是这么简单。为了解决您的问题,有一种叫做“文档”的东西。
    【解决方案3】:

    您可以将 ValidateDevice 方法设为通用方法,让调用者传入实现正确接口组合的对象实例 - 这将允许您的接口保持独立并仍然强制执行类型安全:

    public class DeviceService
    {
       public bool ValidateDevice<T>(T device) where T: IDeviceDataObject, IValidatableObject
       {
           return device.Validate(); 
       }
    }
    

    【讨论】:

      【解决方案4】:

      我从名称中推断出很多,但在我看来 IDeviceDataObjectIValidatableObject 是不同的想法。您可以拥有实现IDeviceDataObjectIValidatableObject 或两者的对象(是吗?),这似乎是合理的。如果这是真的,那么两个接口之间就没有“是”关系(你不会假设IDeviceDataObjectIValidatableObject),所以从另一个接口继承一个接口似乎是错误的。

      至于您的ValidateDevice 方法(或任何方法)——如果要将参数用作IDeviceDataObject,则该参数应该属于该类型。如果要将参数用作IValidatableObject,则参数应该是 that 类型。如果它可能同时使用这两种功能,您可能希望传入一个不太具体的类型,然后执行运行时检查(使用 C# 'is' 或 'as')以查看对象是否支持特定接口。

      【讨论】:

        猜你喜欢
        • 2015-04-28
        • 2021-09-20
        • 1970-01-01
        • 2016-07-18
        • 1970-01-01
        • 2011-10-31
        • 1970-01-01
        • 2018-08-19
        • 1970-01-01
        相关资源
        最近更新 更多