将struct转为sealed类时,隐式转换失败。有问题的结构/类:publicstructHttpMethod{publicstaticreadonlyHttpMethodGet=newHttpMethod("GET");publicstaticreadonlyHttpMethodPost=newHttpMethod("POST");publicstaticreadonlyHttpMethodPut=newHttpMethod("PUT");publicstaticreadonlyHttpMethodPatch=newHttpMethod("PATCH");staticreadonlyHttpMethodDelete=newHttpMethod("DELETE");私有字符串_name;publicHttpMethod(stringname){//名称验证_name=name.ToUpper();}publicstaticimplicitoperatorstring(HttpMethodmethod){returnmethod._name;}publicstaticimplicitoperatorHttpMethod(stringmethod){returnnewHttpMethod(method);}publicstaticboolIsValidHttpMethod(stringmethod){//...}publicoverrideboolEquals(objectobj){//..}publicoverrideintGetHashCode(){return_name.GetHashCode();}publicoverridestringToString(){return_name;以下代码触发问题:publicclassHttpRoute{publicstringPrefix{get;}publicHttpMethod[]方法{get;}publicHttpRoute(stringpattern,paramsHttpMethod[]methods){if(pattern==null)thrownewArgumentNullException(nameof(pattern));=模式;方法=方法??新的HttpMethod[0];}publicboolCanAccept(HttpListenerRequestrequest){returnMethods.Contains(request.HttpMethod)&&request.Url.AbsolutePath.StartsWith(Prefix);改为密封类创建编译错误返回Methods.Contains(request.HttpMethod)报错,注意:request.HttpMethod在本例中是一个字符串。产生以下内容:错误CS1929'HttpMethod[]'不包含'Contains'的定义和最佳扩展方法重载'Queryable.Contains(IQueryable,string)'需要类型为'IQueryable'的接收器我的问题是为什么?我可以重新设计代码以使其工作,但我想知道为什么从结构更改为密封类会出现这个奇怪的错误。编辑:添加了一组简化的示例代码(可在此处获得:https://dotnetfiddle.net/IZ9OXg)。请注意,在第二个类上注释掉字符串的隐式运算符允许代码编译:publicstaticvoidMain(){HttpMethod1[]Methods1=newHttpMethod1[10];HttpMethod2[]Methods2=newHttpMethod2[10];varres1=Methods1.Contains("blah");//有效varres2=Methods2.Contains("blah");//不起作用}publicstructHttpMethod1{publicstaticimplicitoperatorHttpMethod1(stringmethod){returnnewHttpMethod1();}publicstaticimplicitoperatorstring(HttpMethod1方法){return"";}}publicclassHttpMethod2{publicstaticimplicitoperatorHttpMethod2(stringmethod){returnnewHttpMethod2()and}//注释掉它工作正常publicstaticimplicitoperatorstring(HttpMethod2method){return"";我知道的事情:我怀疑但需要确认的事情:更新:这是一个显示问题的程序片段;更新您的转换以转换为C而不是字符串:返回真;}publicstaticvoidMain(){IFoom1=null;IFoom2=null;varres1=Contains(m1,newC());//有效varres2=Contains(m2,newC());//不起作用}}这看起来像类型推断一个可能的错误,如果是这样,那是我的错;如果是这样的话,我会很抱歉,遗憾的是我今天没有时间进一步研究它。您可能想在github上打开一个问题,让某人仍然以此为生。我很想知道结果是什么,以及它是否是设计或推理算法实现中的错误。首先,这是在结构和类之间观察到的行为差异。在这种情况下,您已经“密封”了您的班级这一事实不会影响结果。此外,由于隐式运算符,我们知道以下语句将按预期编译为声明为结构和类的HttpMethod类型。字符串方法=HttpMethods[0];处理数组引入了一些鲜为人知的编译器细微差别。协方差当HttpMethod是类(引用类型)时,使用数组,例如HttpRoute.HttpMethods数组协方差(12.5C#5.0语言规范)发挥作用,允许将HttpMethod[x]视为对象。协变会尊重内置的隐式引用转换(例如类型继承或对象转换),它会尊重显式运算符,但不会尊重或寻找用户定义的隐式运算符。(虽然有点含糊,实际的规范文档列出了默认的隐式和显式运算符,它没有提到用户定义的运算符,但看到其他所有内容都如此高度指定,你可以推断出不支持用户定义的运算符。)基本上,优先于许多通用类型评估协方差。稍后会详细介绍。尤其是数组协变不会扩展到值类型数组。例如,没有允许将int[]视为object[]的转换。因此,当HttpMethod是结构(值类型)时,协变不再是问题,并且将应用来自System.Linq命名空间的以下通用扩展:publicstaticboolContains(thisIEnumerablesource,TSourcevalue);因为你有一个字符串比较器被传入,所以Contains语句将评估如下:publicstaticboolContains(thisIEnumerablesource,stringvalue);当HttpMethod是一个类(引用类型)时,其HttpMethod的当前形式由于协方差[]只能与Object[]相媲美,所以IEnumerable,而不是IEnumerable,何乐而不为呢?因为编译器需要能够判断产生IEnumerable的泛型实现的类型,判断它是否可以进行从Object到T的显式转换。换句话说,编译器无法判断T是否一定可以是字符串或者不,所以它没有找到我们在Linq扩展方法中期望的匹配项。所以你对此能做些什么?(!不是这个!)第一个常见的尝试可能是尝试.Cast()将HttpMethod实例转换为字符串以进行比较:returnHttpMethods.Cast().Contains(request.Method)&&request.Url。AbsolutePath.StartsWith(前缀);你会发现这不起作用。Cast的参数虽然是IEnumerable类型,但不是IEnumerable。它允许您使用未通过LINQ实现IEnumerable通用版本的遗留集合。Cast仅用于通过评估引用类型的共同来源或值类型的拆箱过程,将非泛型对象转换为其“真实”类型。如果装箱和拆箱(C#编程指南)仅适用于值类型(结构),并且由于我们的HttpMethod类型是引用类型(类),那么HttpMethod和String之间唯一的共同来源是Object。HttpMethod上没有接受Object的隐式或显式运算符,因为它不是值类型,因此编译器无法使用任何内置拆箱运算符。请注意,当HttpMethod是值类型(类)时,此Cast将在运行时失败,编译器将很乐意让它构建。最终解决方法我们需要强制将HttpMethods数组中的元素显式转换为字符串(这仍将使用隐式运算符!)而不是Cast或依赖隐式转换,但Linq再次使这变得微不足道,但这是一项必要的任务:以上是C#学习教程:struct转sealedclass时,隐式转换无法共享所有内容。如果对大家有用,需要进一步了解C#学习教程,希望大家多多关注——returnHttpMethods.Select(c=>(string)c).Contains(request.Method)&&request.Url.AbsolutePath.StartsWith(前缀);本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理会员删除。如需转载请注明出处:
