将结构更改为密封类时,隐式转换失败 [英] Implicit conversion fails when changing struct to sealed class
问题描述
有问题的结构/类:
public struct HttpMethod
{
public static readonly HttpMethod Get = new HttpMethod("GET");
public static readonly HttpMethod Post = new HttpMethod("POST");
public static readonly HttpMethod Put = new HttpMethod("PUT");
public static readonly HttpMethod Patch = new HttpMethod("PATCH");
public static readonly HttpMethod Delete = new HttpMethod("DELETE");
private string _name;
public HttpMethod(string name)
{
// validation of name
_name = name.ToUpper();
}
public static implicit operator string(HttpMethod method)
{
return method._name;
}
public static implicit operator HttpMethod(string method)
{
return new HttpMethod(method);
}
public static bool IsValidHttpMethod(string method)
{
// ...
}
public override bool Equals(object obj)
{
// ...
}
public override int GetHashCode()
{
return _name.GetHashCode();
}
public override string ToString()
{
return _name;
}
}
以下代码触发了该问题:
The following code triggers the issue:
public class HttpRoute
{
public string Prefix { get; }
public HttpMethod[] Methods { get; }
public HttpRoute(string pattern, params HttpMethod[] methods)
{
if (pattern == null) throw new ArgumentNullException(nameof(pattern));
Prefix = pattern;
Methods = methods ?? new HttpMethod[0];
}
public bool CanAccept(HttpListenerRequest request)
{
return Methods.Contains(request.HttpMethod) && request.Url.AbsolutePath.StartsWith(Prefix);
}
}
编译器错误是通过将HttpMethod结构更改为密封课。对于 return Methods.Contains(request.HttpMethod)
报告错误,请注意: request.HttpMethod
在这种情况下是字符串
。产生以下内容:
The compiler error is created by changing the HttpMethod struct into a sealed class. The error is reported for return Methods.Contains(request.HttpMethod)
, note: request.HttpMethod
in this case is a string
. Which produces the following:
Error CS1929 'HttpMethod[]' does not contain a definition for 'Contains' and the best extension method overload 'Queryable.Contains<string>(IQueryable<string>, string)' requires a receiver of type 'IQueryable<string>'
我的问题是为什么?我可以重新设计代码以使其正常工作,但是我想知道为什么从struct转换为Sealed类会导致此奇怪的错误。
My question is why? I can redesign the code to make it work, but I'm wanting to know why changing from struct to sealed class creates this weird error.
编辑:添加一组简化的示例代码(可在此处找到: https://dotnetfiddle.net/IZ9OXg )。请注意,在第二类上将 out 隐式运算符注释为字符串允许代码进行编译:
Edit: Adding a simplified set of example code (available here: https://dotnetfiddle.net/IZ9OXg). Take note that commenting out the implicit operator to string on the second class allows the code to compile:
public static void Main()
{
HttpMethod1[] Methods1 = new HttpMethod1[10];
HttpMethod2[] Methods2 = new HttpMethod2[10];
var res1 = Methods1.Contains("blah"); //works
var res2 = Methods2.Contains("blah"); //doesn't work
}
public struct HttpMethod1
{
public static implicit operator HttpMethod1(string method)
{
return new HttpMethod1();
}
public static implicit operator string (HttpMethod1 method)
{
return "";
}
}
public class HttpMethod2
{
public static implicit operator HttpMethod2(string method)
{
return new HttpMethod2();
}
//Comment out this method and it works fine
public static implicit operator string (HttpMethod2 method)
{
return "";
}
}
推荐答案
我知道的事情
- 很明显,问题出在类型推断上。
- 在第一种情况下,T被推导为HttpMethod1。
- 在struct情况下,没有从
HttpMethod1 []
到<$的转换。 c $ c> IEnumerable< string> ,因为协方差仅适用于引用类型。 - 在类情况下,
没有转换HttpMethod2 []
到IEnumerable< string>
的原因是协方差仅适用于引用转换,这是用户定义的转换。
- Plainly the problem is in type inference.
- In the first case, T is deduced to be HttpMethod1.
- In the struct case, there is no conversion from
HttpMethod1[]
toIEnumerable<string>
because covariance only works on reference types. - In the class case, there is no conversion from
HttpMethod2[]
toIEnumerable<string>
because covariance only works on reference conversions, and this is a user-defined conversion.
我怀疑但需要确认的东西
Things I suspect but need to confirm:
- 关于最后两点之间的细微差别使类型推断算法混乱。
更新:
- 与协变数组转换无关。即使没有数组转换,问题也会再次出现。
- 确实确实如此,但是与协变接口转换有关。
- 它具有与字符串无关。 (字符串通常有点怪异,因为它们难以转换为
IEnumerable< char>
,偶尔会搞乱类型推断。)
- It has nothing to do with covariant array conversions. The problem repros even without array conversions.
- It does however have to do with covariant interface conversions.
- It has nothing to do with strings. (Strings are often a bit weird because they have a hard-to-remember conversion to
IEnumerable<char>
that occasionally messes up type inference.)
这是一个显示问题的程序片段;更新您的转换以转换为C而不是字符串:
Here's a program fragment that displays the problem; update your conversions to convert to C instead of string:
public interface IFoo<out T> {}
public class C {}
public class Program
{
public static bool Contains<T>(IFoo<T> items, T item)
{
System.Console.WriteLine(typeof(T));
return true;
}
public static void Main()
{
IFoo<HttpMethod1> m1 = null;
IFoo<HttpMethod2> m2 = null;
var res1 = Contains(m1, new C()); //works
var res2 = Contains(m2, new C()); //doesn't work
}
}
类型推断中的错误,如果是,那是我的错;如果是这样的话,很多道歉。可悲的是,我今天没有时间进一步研究它。您可能想在github上打开一个问题,并请有人仍对此进行生动的研究。我会着迷于了解结果是什么,以及如果发现它是推理算法的设计或实现中的错误。
This looks like a possible bug in type inference, and if it is, it is my fault; many apologies if that is the case. Sadly I do not have time to look into it further today. You might want to open an issue on github and have someone who still does this for a living look into it. I would be fascinated to learn what the result was, and if it turns out to be a bug in either the design or the implementation of the inference algorithm.
这篇关于将结构更改为密封类时,隐式转换失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!