将结构更改为密封类时,隐式转换失败 [英] Implicit conversion fails when changing struct to sealed class

查看:87
本文介绍了将结构更改为密封类时,隐式转换失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有问题的结构/类:

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[] to IEnumerable<string> because covariance only works on reference types.
  • In the class case, there is no conversion from HttpMethod2[] to IEnumerable<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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆