Laz*_*zlo 5 c# generics design-patterns interface
我开始看到这种模式经常出现在我的代码中:
class Foo { }
interface IBar
{
Foo Foo { get; }
}
class Bar<TFoo> : IBar where TFoo : Foo
{
public TFoo Foo { get; private set; }
Foo IBar.Foo
{
get
{
return Foo;
}
}
}
Run Code Online (Sandbox Code Playgroud)
它的一些好处是:
if (something is IBar))的简单方法TFoo封闭构造的Bar<>s 中的强类型访问Foo接口中IBar的多态访问有人可能会争辩说,这种模式在框架中无处不在(例如List<T> : IList),但我想知道这是否只是 .NET 1.0 的残余,当泛型不存在时。
在我的脑海里,我主要担心的是,这IBar不一定是一个适当的合同,它定义了“酒吧”应该提供什么成员;访问通用类型的成员只是一种技巧。
此外,如果我开始为此目的添加接口,我很快就会难以维护并行继承层次结构。
我应该担心在我的代码库中传播这种模式吗?如果是这样,哪些替代模式可以提供上面列出的部分或全部 3 个好处?
因为不允许显式实现抽象成员,所以这个“理想”的解决方案是不可能的:
class Foo { }
class Bar
{
public abstract Foo Foo { get; }
}
class Bar<TFoo> : Bar where TFoo : Foo
{
private TFoo foo;
Foo Bar.Foo
{
get
{
return foo;
}
}
public new TFoo Foo
{
get
{
return foo;
}
}
}
Run Code Online (Sandbox Code Playgroud)
回想起来,我了解到我想要的正确术语是返回类型协方差,不幸的是C# 不支持它,因为语言设计团队没有考虑实现该功能的好处超过成本,即使它保留了类型安全。(已经起草并完成了一项提案,但似乎已被放弃)。
使用返回类型协方差,示例代码可以写为:
class Foo { }
class Bar
{
public virtual Foo Foo { get; }
}
class Bar<TFoo> : Bar where TFoo : Foo
{
public override TFoo Foo { get; }
}
Run Code Online (Sandbox Code Playgroud)
Eric Lippert 在该相关问题中提出的解决方法是:
class Foo { }
abstract class Bar
{
protected abstract Foo foo { get; }
public Foo Foo => foo;
}
class Bar<TFoo> : Bar where TFoo : Foo
{
protected override Foo foo => this.Foo;
public new TFoo Foo { get { ... } }
}
Run Code Online (Sandbox Code Playgroud)
它的缺点是不复制继承层次结构,而是复制每个继承级别的每个协变模拟属性!
要进一步了解模拟协变返回类型会给代码带来多少混乱,请考虑正确实现意味着在每个继承级别ICloneable添加另一个虚拟方法。我将将此作为我对该语言功能的谦卑请求。
| 归档时间: |
|
| 查看次数: |
897 次 |
| 最近记录: |