gpt4 book ai didi

c# - 在不违反空接口(interface)规则的情况下创建协变泛型类型

转载 作者:太空宇宙 更新时间:2023-11-03 10:22:27 25 4
gpt4 key购买 nike

背景:我想“扩展”.NET Lazy<>类型以支持 Lazy<T> 之间的隐式转换和基础 T对象能够自动解包包含的值。我能够相当轻松地做到这一点:

public class ExtendedLazy<T> : Lazy<T>
{
public ExtendedLazy() : base() {}
public ExtendedLazy(bool isThreadSafe) : base(isThreadSafe) { }
public ExtendedLazy(Func<T> valueFactory) : base(valueFactory) { }
// other constructors

public static implicit operator T(ExtendedLazy<T> obj)
{
return obj.Value;
}
}

我想通过制作 T 更进一步协变,所以我可以分配 ExtendedLazy<Derived> 的实例至 ExtendedLazy<Base> .由于类定义中不允许使用方差修饰符,因此我不得不求助于一个空接口(interface)来实现这一点:

public interface IExtendedLazy<out T>
{
}

并将我的类定义更改为

public class ExtendedLazy<T> : Lazy<T>, IExtendedLazy<T>

这工作正常,我能够利用这种协变类型:

ExtendedLazy<DerivedClass> derivedLazy = new ExtendedLazy<DerivedClass>();
IExtendedLazy<BaseClass> baseLazy = derivedLazy;

虽然这可以编译并且工作正常,但它违反了 CA1040: Avoid empty interfaces它说使用空接口(interface)作为契约是一个糟糕的设计和代码味道(我相信大多数人都同意)。我的问题是,鉴于 CLR 无法识别类定义中的变体泛型类型,还有什么其他方法可以使其与可接受的 OO 实践更加一致?我想我不是唯一面临这个问题的人,所以我希望能对此有所了解。

最佳答案

您的逻辑不会像您认为的那样有效。

ExtendedLazy<DerivedClass> derivedLazy = new ExtendedLazy<DerivedClass>();
IExtendedLazy<BaseClass> baseLazy = derivedLazy;
BaseClass v = baseLazy;

这不会编译,因为不存在来自 IExtendedLazy<BaseClass> 的转换至 BaseClass因为转换运算符仅为 ExtendedLazy<T> 定义.

这将迫使您在使用界面时做其他事情。添加T Value { get; }既解决了 CA1040 的问题,又让您可以访问潜在的值(value)。

顺便说一句 Lazy<T> 的原因不提供 implicit operator T是因为底层Func<T>可能会引发混淆,因为引发的行很可能没有函数(或属性)调用。

关于c# - 在不违反空接口(interface)规则的情况下创建协变泛型类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32897075/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com