接口方法

时间:2018-04-09 11:15:45

标签: c# .net generics interface

我在我的界面中执行以下操作,原因是我不希望在我的IEquipmentDataProvider实现中与IEquipment的实现紧密耦合

public interface IEquipmentDataProvider
{
  IEquipment GetEquipment<E>(string Path) where E : IEquipment, new();
}

但我认为类型约束应留给实现,我应该在我的界面中声明IEquipment GetEquipment(string path);。但是,如果我这样做,它是冗余方法的接口,因为该方法永远不会被调用。

在接口方法中实现类型约束是否可以,或者我应该考虑另一种模式?

编辑: 我这样做的原因是因为我不希望我的数据访问层必须使用IEquipment的具体实现,我可以将其留给域逻辑层。因此使用泛型,这将是IEquipment的一个实例,但由dll决定。用

打电话
Equipment eq = da.GetEquipment<Equipment>("somepath"); // where eq is Iequipment, and da is IEquipmentDataProvider

2 个答案:

答案 0 :(得分:1)

  

但我认为类型约束应留给实现,我应该只声明IEquipment GetEquipment(字符串路径);在我的界面中。

虽然我可以看到你的意思,但我确实认为它与此相关。忽略您的类型约束,您的界面定义非常清楚这是否适用于设备

  • IEquipmentDataProvider
  • GetEquipment()
  • 返回类型IEquipment

您希望将可用类型限制为实施IEquipment的类型,这几乎是不可避免的。

以下内容对您有意义吗?这是一个预期的用例吗?

public class StringProvider : IEquipmentDataProvider
{
    //...
}

var provider = new StringProvider();
var equipment = provider.GetEquipment<string>(myPath);

我很确定它没有。因为使用IEquipment实现以外的任何内容都没有意义。

我认为这个问题比你现在讨论的要大。我看到其他一些小的不一致之处:

  • 您创建了一个通用的E类型参数,但您的返回值是IEquipment类型。为什么?为什么不让E返回类型?现有代码(例如IEquipment myEquipment = myProvider.GetEquipment())仍可在不需要更改的情况下运行,并且您可以选择在需要时返回特定类型。
  • 我不太明白为什么这个方法是通用的,但类/接口本身并不是。泛型方法有一些用例,但是你的用例似乎更适合通用的类/接口。

我想进一步解决第二个要点。实施后,您的界面将确保每个实施都能获得每种类型的`IEquipment。

将此与通用类版本进行比较:

public interface IEquipmentDataProvider<E> where E : IEquipment, new()
{
    E GetEquipment<E>(string Path);
}

几乎相同的代码。但是现在,您可以专门或通用地实现这些接口,但是您想要它

public class HammerDataProvider : IEquipmentDataProvider<Hammer> {}

public class SawDataProvider : IEquipmentDataProvider<Saw> {}

public class AllEquipmentDataProvider : IEquipmentDataProvider<IEquipment> {}

IEquipmentDataProvider的每个实现都可以选择将自己限制为特定类型(HammerSaw),或者它可以处理IEquipment的每个实现。

修改
这也允许您组合多个接口,这些接口可以在同一个类中单独实现:

public class HammerAndSawDataProvider : IEquipmentDataProvider<Hammer>, IEquipmentDataProvider<Saw> {}

由于两种界面方法之间缺乏类型区分,您需要依赖explicit interface implementation。也许不是你想要的。
如果您的接口方法在不同的泛型类型之间有不同的签名(例如 GetEquipment<E>(E myEquipment) ),那么您可以避免使用显式接口实现。

这可能是您的要求过了一步,但它确实展示了您可以绝对控制哪个设备可以由特定提供商处理。

总结

  • 根据您用于类和方法的命名,类型约束似乎是给定的。
  • 使用偏离建议的类型约束的类型几乎没有任何意义。
  • 如果您已使用通用类型;你的返回类型是通用类型会更好。在最坏的情况下,它不会破坏任何东西。最好的情况是,它允许更好的类型安全性和更少的硬铸造(例如,它不需要在Hammer myHammer = (Hammer)provider.GetEquipment(myPath);中执行演员表。)
  • 通常,您希望在类/接口级别使用泛型参数。泛型方法(没有泛型类)的主要缺点是您必须为在toplevel方法中调用的每个子方法重复定义类型约束。通用方法(没有通用类)通常只在&#34; toolkit&#34;中得到了真正的保证。方法,就我现在所能想到的而言。
  • 迂腐:我会将通用参数重命名为TEquipment(或TE,如果您想要简洁的话)。类型参数通常以某种方式命名。 TElement被读作&#34;元素的类型&#34;。但这是风格和命名惯例的问题。
    • 在您的代码中,您确实遵守以&#34;接口名称开头的I&#34;惯例。通用类型有关于以T开头的类似约定。

对OP更新的回应

  

编辑:我之所以这样做是因为我不希望我的数据访问层必须使用IEquipment的具体实现,我可以将其留给域逻辑层。因此使用泛型,这将是IEquipment的一个实例,但由dll决定。

这有点重申了我的断言,你应该使用泛型类/接口,而不仅仅是泛型方法。

答案 1 :(得分:-1)

如果要解释这行代码,

IEquipment GetEquipment<E>(string Path) where E : IEquipment, new();

它将成为“ GetEquipment泛型方法,其约束类型为IEquipment,其实现具有默认构造函数”

相反,设计可能只是一个显式的接口方法

Equipment eInstance=new Equipment();

IEquipmentDataProvider iEInstance=(IEquipmentIEquipmentDataProvider )eInstance;

iEInstance=iEInstance.GetEquipment(path);

因此,即使您有另一个以不同方式实现GetEquipment方法的类,您也可以使用显式接口方法调用GetEquipment的{​​{1}}方法。

编辑:OP编辑后

IEquipment