对于我.NET 2.0正在进行的项目,我很遗憾(我们的许多目标机器仍然是Windows XP),这意味着Nuget的库 不需要任何Optional类型.Optional.NET 3.5
幸运的是,滚动自己的Optional类型非常简单,但我遇到了一个问题.
我想要以下内容:
class Optional<T> : (IComparable<Optional<T>> when T : IComparable<T>)
Run Code Online (Sandbox Code Playgroud)
也就是说,我希望我的Optional类型能够实现Comparable,但只有当底层类型是Comparable.
上面的语法遗憾地无效,但是有没有办法实现我正在寻找的东西?
实际上这个问题并不局限于Optional它,它将适用于任何想要定义的容器类型,它可以实现它的内部类型的接口.
我意识到我可以做到这一点:
class Optional<T>
class ComparableOptional<T> : Optional<T>, Comparable<ComparableOptional<T>>
where T : Comparable<T>
Run Code Online (Sandbox Code Playgroud)
但这似乎有点傻,因为那时我们真的要走下这个兔子洞:
class Optional<T>
class EquatableOptional<T> :
Optional<T>,
IEquatable<EquatableOptional<T>>
where T : IEquatable<T>
class ComparableOptional<T> :
EquatableOptional<T>,
IComparable<ComparableOptional<T>>,
IEquatable<ComparableOptional<T>>
where T : IComparable<T>
Run Code Online (Sandbox Code Playgroud)
此外,如果T是Enumerable,Optional<T>也可以Enumerable(如果没有值则返回一个空的枚举器),那么我们就有了更多的类.
由于Enumerable是垂直于Equatable和Comparable,我们就真的需要以下类:
class Optional
class EquatableOptional
class ComparableOptional
class EnumerableOptional
class EnumerableEquatableOptional
class EnumerableComparableOptional
Run Code Online (Sandbox Code Playgroud)
涵盖所有案件.添加另一个正交接口,你有12个类.
是否有一个不那么混乱的方法,允许我有条件地定义接口?这似乎是任何集合的常见问题.
您想要做的事情违反了泛型在 C# 中工作的意图。
您本质上是在争论类型安全应该用作类型可能性。这违背了当前的 C# 意识形态,即您知道类型的定义(以及它公开的方法和属性)。
正确的方法是使用第二个方法ComparableOptional<T>,它派生自Optional<T>但添加了额外的约束:
class ComparableOptional<T> : Optional<T> where T : Comparable<T>
Run Code Online (Sandbox Code Playgroud)
除了想要将两个不同的类混在一起的懒惰方法之外,您的建议没有任何好处。即使该语言允许您这样做,我也认为这种方法没有明显的好处(与 相比ComparableOptional<T>),但它确实引入了您现在可能遇到的一系列运行时错误。
class Optional<T> : (IComparable<Optional<T>> when T : IComparable<T>) {}
Run Code Online (Sandbox Code Playgroud)
假设一切都按照您期望的方式进行。
var optionalPerson = new Optional<Person>() { Person = myPerson };
var optionalPerson2 = new Optional<Person>() { Person = myPerson2 };
int result = optionalPerson.CompareTo(optionalPerson2);
Run Code Online (Sandbox Code Playgroud)
这应该有效吗?目前在 C# 中,还没有。但根据你的说法,应该可以 if Person : IComparable<Person>。你的论点应该是这样的:
由于编译器看到我使用 type
Person : IComparable<Person>,它应该能够推断出现Optional<T>在必须实现IComparable<T>,因此CompareTo()应该可用。
您的论点的可靠性仅取决于以下事实:您知道(在编译时)您正在使用的类型实现了所需的接口。
但是这段代码怎么样:
public void DoSomething<T>(Optional<T> opt1, Optional<T> opt2)
{
int result = opt1.CompareTo(opt2);
}
Run Code Online (Sandbox Code Playgroud)
这应该有效吗?你无法知道,因为你不知道将使用哪种类型!使问题进一步复杂化:
public void DoSomething(string optionalType, object opt1, object opt2)
{
var castObj = Convert.ChangeType(opt1, Type.GetType(optionalType)));
var castObj2 = Convert.ChangeType(opt2, Type.GetType(optionalType)));
int result = castObj .CompareTo(castObj2);
}
Run Code Online (Sandbox Code Playgroud)
此方法将使用的类型作为字符串传递。因此,现在您希望编译器检查字符串的值,以确定字符串中表示的类型的泛型类型约束是否实现特定的接口。
如果从数据库或外部 Web 服务检索该字符串会怎么样?编译器现在是否需要具有活动的数据库/Web 连接才能确定您的代码是否有效?
这已经失控了。
您可能的反驳:
只要我只将此方法与实现的类型一起使用
IComparable<T>,编译器就不会抛出错误。当我使用未实现的类型时IComparable<T>,它应该会抛出错误int result。
这不直观,并且会导致开发人员感到困惑。
编译器应始终假设条件泛型类型约束为 true。
那么,您将如何处理互斥的条件泛型类型约束,从逻辑上讲,它们永远不会同时成立?
欢迎来到调试地狱的世界。这是一种不好的做法,其原因与您不应该使用dynamic强类型方法的原因相同:它使代码相当难以维护和开发。
这种方法需要更多的运行时测试,以确保您没有在某个地方犯下会在您面前爆炸的错误。运行时测试是一种有缺陷的方法。
| 归档时间: |
|
| 查看次数: |
476 次 |
| 最近记录: |