【问题标题】:C# overload resolution and genericsC# 重载解析和泛型
【发布时间】:2022-12-06 21:23:24
【问题描述】:

我有以下方法

public static EnumerableAssertions<T> AssertThat<T>(IEnumerable<T> collection)
{
    Debug.WriteLine("Enumerable!");
    return new EnumerableAssertions<T>(collection);
}

public static ObjectAssertions<T> AssertThat<T>(T value) where T : class
{
    Debug.WriteLine("Generic fallback!");
    return new ObjectAssertions<T>(value);
}

但是为什么下面的调用解析为通用回退?

List<object> list = null;
AssertThat(list);

根据我的理解,IEnumerable&lt;T&gt; 的重载应该比通用的 T : class 更具体,但 C# 似乎对此有不同的看法。如果我为精确的输入 List&lt;T&gt; 它工作得很好,但我当然不想为每个继承 IEnumerable&lt;T&gt; 的类型添加特定的重载

[编辑] 这个也不起作用:

public static EnumerableAssertions<TCollection> AssertThat<TCollection, T>(TCollection collection) where TCollection : IEnumerable<T>
{
    Debug.WriteLine("Enumerable #2!");
    return new EnumerableAssertions<T>(collection);
}

【问题讨论】:

  • 无论如何你为什么要使用List&lt;object&gt;
  • @Deleted 如果您更喜欢它,请将其设为 List<string> 并且问题不会改变。这是一个例子。
  • 顺便说一句,如果您提供string,您希望它选择哪个重载?请记住,那种类型发生成为IEnumerable&lt;char&gt;,但这不是最常见的思考方式。
  • 苹果和橙子. AssertThat&lt;T&gt;(T value) 包含显式约束 where T : classAssertThat&lt;T&gt;(IEnumerable&lt;T&gt; collection) 具有完全没有明确的约束。 AssertThat(list); 最有可能解析为通用类型,因为 List&lt;&gt; 是引用类型,比不受限制的 IEnumerable&lt;T&gt; 更符合 where T : class
  • “我知道这些是苹果和橘子,但即使是超载”- 无关紧要。问题出在你的代码上,而不是他们的。

标签: c# overloading overload-resolution


【解决方案1】:

操作员:

根据我的理解,IEnumerable 的重载应该比泛型 T : 类更具体,但 C# 似乎有不同的看法

苹果和橙子。

这个方法:

public static ObjectAssertions<T> AssertThat<T>(T value) where T : class

...包含显式约束:

where T : class

...同时:

public static EnumerableAssertions<T> AssertThat<T>(IEnumerable<T> collection)

...有完全没有明确的约束.

操作员:

但是为什么下面的调用解析为通用回退?

编码:

List<object> list = null;
AssertThat(list);

...最有可能解析为通用类型(带有 where T : class 的那个),因为 List&lt;&gt; 是一种引用类型,比 where T : class 更符合 where T : class不受限制的IEnumerable&lt;T&gt;.

【讨论】:

  • 但是,规则“是引用类型”不应该是所有其他可能性都用尽后的最后退路吗?那么使用EnumerableAssertions&lt;T&gt; AssertThat&lt;TCollection, T&gt;(TCollection value) where TCollection : IEnumerable&lt;T&gt;呢?这有一个明确的约束,不是吗?
  • 我不确定你为什么一直提到EnumerableAssertions&lt;T&gt;。如果 c# 决定不调用 AssertThat&lt;T&gt;(IEnumerable&lt;T&gt; collection),那么方法体内的任何内容都没有实际意义。
  • “但是规则‘是引用类型’不应该是……”- 你有责任解释为什么你认为 C# 应该按照你认为应该的方式行事,通过不对你的 AssertThat&lt;T&gt;(IEnumerable&lt;T&gt; ) 方法施加足够的限制,将它开放给 List&lt;int&gt; 的调用者,因为 T 在你的代码可以是值类型.您似乎对泛型和泛型约束的工作方式存在根本性的误解。考虑使用更具体的引用类型(而不仅仅是 object 和值类型)进行更多实验,并在调试器中单步执行代码。祝你好运!
  • EnumerableAssertions&lt;T&gt; AssertThat&lt;TCollection, T&gt;(TCollection value) where TCollection : IEnumerable&lt;T&gt;?这有一个明确的约束,不是吗?”- 重要的是,在尝试学习时,不要有态度。现在回到代码。虽然它对 value 有限制 - 必须是 IEnumerable&lt;T&gt;它没有说明T 是什么所以我可以传递IEnumerable&lt;float&gt;。现在float不是是引用类型吗?当然不是....
  • ...就像我说的,问题不在于他们的代码,而在于你的你试图将 List&lt;object&gt; 压缩到可能需要 IEnumerable&lt;float&gt; 的东西中,你想知道为什么 C# 决定采用正确的路径来自AssertThat&lt;T&gt;(T value) where T : class。这“秘密酱汁”在这种情况下是where T : class
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-20
  • 2013-03-16
  • 1970-01-01
相关资源
最近更新 更多