简体   繁体   English

有关C#语言规范中隐式转换的问题

[英]Question regarding implicit conversions in the C# language specification

Section 6.1 Implicit conversions defines an identity conversion thusly: 6.1节隐式 转换因此定义了身份转换

An identity conversion converts from any type to the same type. 身份转换从任何类型转换为相同类型。 This conversion exists such that an entity that already has a required type can be said to be convertible to that type. 存在这种转换,使得已经具有所需类型的实体可以说可转换为该类型。

Now, what is the purpose of sentences such as these? 现在,这些句子的目的是什么?

(In §6.1.6 Implicit reference conversions) (在§6.1.6隐式参考转换中)

The implicit reference conversions are: 隐式引用转换是:

  • [...] [...]
  • From any reference-type to a reference-type T if it has an implicit identity or reference conversion to a reference-type T 0 and T 0 has an identity conversion to T . 从任何引用类型引用类型 T如果它具有对引用类型 T 0的隐式标识或引用转换,则T 0具有到T的标识转换。

and: 和:

(In §6.1.7 Boxing conversions) (在§6.1.7拳击转换中)

  • A value type has a boxing conversion to an interface type I if it has a boxing conversion to an interface type I 0 and I 0 has an identity conversion to I . 如果值类型具有到接口类型I 0的装箱转换并且I 0具有到I的标识转换,则值类型具有到接口类型I的装箱转换。

Initially they seem redundant (tautologous). 最初它们似乎是多余的(同义词)。 But they must be there for a purpose, so why are they there? 但他们必须出于某种目的,所以为什么他们在那里?

Can you give an example of two types T 1 , T 2 such that T 1 would not be implicitly convertible to T 2 if it weren't for the above-quoted paragraphs? 你能给出一个T 1T 2这两种类型的例子,如果不是上面引用的段落, T 1不能隐式转换为T 2吗?

Update on 22-Sep-2010: 2010年9月22日更新:

I doubt anybody is going to read this besides Timwi. 我怀疑除了蒂姆维之外还有人会读这个。 Even so, I wanted to make a few edits to this answer in light of the fact that a new answer has now been accepted and the debate still continues (at least in my perhaps imaginary world) on whether or not the quoted excerpts of the spec are technically redundant. 即便如此,我想对这个答案进行一些编辑,因为现在已经接受了一个新的答案,并且辩论仍在继续(至少在我想象的世界中)是否引用了规范的摘录在技​​术上是多余的。 I am not adding much, but it's too substantial to fit in a comment. 我并没有增加太多,但它太大了,不适合评论。 The bulk of the update can be found under the heading "Conversion involving the dynamic type" below. 大部分更新可以在下面的“涉及dynamic类型的转换 ”标题下找到。


Update on 19-Sep-2010: 2010年9月19日更新:

In your comment: 在你的评论中:

[T]his doesn't make sense. [T]他没有意义。

Damn, Timwi, you say that a lot . 该死的,蒂姆维,你说的很多 But all right, then; 但是好吧,那么; you've put me on the defensive, so here goes! 你让我处于守势,所以来吧!

Disclaimer: I have definitely not examined the spec as closely as you have. 免责声明:我绝对没有像你一样仔细检查规格。 Based on some of your recent questions it seems like you've been looking into it quite a bit lately. 基于你最近的一些问题,你好像最近一直在研究它。 This is naturally going to make you more familiar with a lot of details than most users on SO; 这自然会让你比SO上的大多数用户更熟悉很多细节; so this, like most answers you're likely to receive from anyone other than Eric Lippert, may not satisfy you. 所以,就像你从Eric Lippert以外的任何人那里收到的大多数答案一样,这可能不会让你满意。

Different premises 不同的前提

Firstly, the premise of your question is that if the statements highlighted are redundant , then they serve no purpose . 首先,你的问题的前提是,如果突出显示的陈述是多余的 ,那么它们就没有用处 My answer's premise is that redundant statements are not necessarily without purpose if they clarify something that isn't obvious to everyone . 我的答案的前提是,如果多余的陈述澄清了对每个人都不明显的东西,那么多余的陈述并不一定没有目的。 These are contradictory premises. 这些是相互矛盾的前提。 And if we can't agree on premises, we can't have a straightforward logical argument. 如果我们不能就前提达成一致,我们就不能有一个直截了当的逻辑论证。 I was simply asking you to rethink your premise. 我只是想让你重新思考你的前提。

Your response, however, was to reiterate your premise: "If the sentences are truly redundant, then they only confuse the reader and don't clarify anything." 然而,你的回答是重申你的前提:“如果句子真的是多余的,那么他们只会混淆读者而不澄清任何事情。”

(I like how you set yourself up as the representative for all readers of the spec there, by the way.) (顺便说一句,我喜欢你如何让自己成为所有规范读者的代表。)

I can't blame you for holding this position, exactly. 我完全不能责怪你担任这个职位。 I mean, it does seem obvious. 我的意思是,这似乎显而易见。 And I didn't give any concrete examples in my original answer. 我的原始答案中没有给出任何具体的例子。 So below I will try to include some concrete examples. 所以下面我将尝试包括一些具体的例子。 But first, let me take a step back and offer my take on why this weird identity conversion concept exists in the spec in the first place. 但首先,让我退后一步,提出我为什么这个奇怪的身份转换概念首先存在于规范中。

The purpose of the identity conversion definition 身份转换定义的目的

Upon first glance, this definition seems rather superfluous; 乍一看,这个定义似乎是多余的; isn't it just saying that an instance of any type T is convertible to ... well, to T? 是不是只是说任何类型T的实例都可以转换为......好吧,到T? Yes, it is. 是的。 But I hypothesize* that the purpose of this definition is to provide the spec with the proper vocabulary to utilize the concept of type identity in the context of discussing conversions . 但我假设*这个定义的目的是为规范提供适当的词汇,以便在讨论转换的过程中利用类型身份的概念。

This allows for statements about conversions which are essentially transitive in nature. 这允许有关转换的陈述本质上是可传递的。 The first point you quoted from the spec as an example of a tautological statement falls into this category. 您从规范中引用的第一点作为重言式声明的一个例子属于这一类。 It says that if an implicit conversion is defined for some type (I'll call it K) to another type T 0 and T 0 has an identity conversion to T, then K is implicitly convertible to T. By the definition of identity conversion given above, "has an identity conversion to" really means "is the same type as." 它表示如果为某种类型(我将其称之为K)定义了隐式转换为另一种类型T 0并且T 0 具有到 T 的标识转换 ,那么K可以隐式转换为T.通过给定标识转换的定义上面,“有一个身份转换为”真正意味着“是同一类型。” So the statement is redundant . 所以声明是多余的

But again: the identity conversion definition exists in the first place to equip the spec with a formal language for describing conversions without having to say things like "if T 0 and T are really the same type." 但同样重要的是: 身份转换定义首先存在于为规范配备描述转换的形式语言,而不必说“如果T 0和T真的是同一类型”。

OK, time for concrete examples. 好的,具体例子的时间。

Where the existence of an implicit conversion might not be obvious to some developers 对于某些开发人员而言,隐式转换的存在可能并不明显

Note: A much better example has been provided by Eric Lippert in his answer to the question . 注意:Eric Lippert在回答这个问题时提供了一个更好的例子。 I leave these first two examples as only minor reinforcements of my point. 我把这前两个例子留作我的观点的一点点补充。 I have also added a third example that concretizes the identity conversion that exists between object and dynamic as pointed out in Eric's answer. 我还添加了第三个例子,它将objectdynamic之间存在的身份转换具体化,如Eric的回答所指出的那样。

Transitive reference conversion 传递参考转换

Let's say you have two types, M and N , and you've got an implicit conversion defined like this: 假设您有两种类型, MN ,并且您有一个如下定义的隐式转换:

public static implicit operator M(N n);

Then you can write code like this: 然后你可以写这样的代码:

N n = new N();
M m = n;

Now let's say you've got a file with this using statement up top: 现在让我们说你有一个带有这个using语句的文件:

using K = M;

And then you have, later in the file: 然后你在文件的后面有:

N n = new N();
K k = n;

OK, before I proceed, I realize that this is obvious to you and me . 好的,在我继续之前,我意识到这对 我来说是显而易见的。 But my answer is, and has been from the beginning, that it might not be obvious to everyone , and therefore specifying it--while redundant --still has a purpose . 但我的回答是,从一开始就是这样,对每个人来说可能并不明显,因此指明它 - 虽然多余 -仍然有目的

That purpose is: to make clear to anyone scratching his or her head, looking at that code, it is legal. 这样做的目的是:为了清楚任何人抓挠他们的头,看看那个代码,这是合法的。 An implicit conversion exists from N to M, and an identity conversion exists from M to K (ie, M and K are the same type); 存在从N到M的隐式转换 ,并且存在从M到K的身份转换 (即,M和K是相同的类型); so an implicit conversion exists from N to K. It isn't just logical (though it may be logical); 因此存在从N到K的隐式转换。它不仅仅是逻辑的(尽管它可能合乎逻辑的); it's right there in the spec . 它就在规范中 Otherwise one might mistakenly believe that something like the following would be necessary: 否则,人们可能会错误地认为需要以下内容:

K k = (M)n;

Clearly, it isn't. 显然,事实并非如此。

Transitive boxing conversion 传递拳击转换

Or take the type int . 或者采用int类型。 An int can be boxed as an IComparable<int> , right? int可以装箱为IComparable<int> ,对吧? So this is legal: 所以这是合法的:

int i = 10;
IComparable<int> x = i;

Now consider this: 现在考虑一下:

int i = 10;
IComparable<System.Int32> x = i;

Again, yes , it may be obvious to you, me, and 90% of all developers who might ever come across it. 再次, 是的 ,对于您,我和90%可能遇到过它的开发人员来说,这可能是显而易见的 But for that slim minority who don't see it right away: a boxing conversion exists from int to IComparable<int> , and an identity conversion exists from IComparable<int> to IComparable<System.Int32> (ie, IComparable<int> and IComparable<System.Int32> are the same type); 但对于那些看不到它的苗条少数人来说:从intIComparable<int>存在一个拳击转换 ,并且存在从IComparable<int>IComparable<System.Int32>身份转换 (即IComparable<int>IComparable<System.Int32>是相同的类型); so a boxing conversion exists from int to IComparable<System.Int32> . 所以从intIComparable<System.Int32>存在一个装箱转换。

Conversion involving the dynamic type 涉及dynamic类型的转换

I'm going to borrow from my reference conversion example above and just tweak it slightly to illustrate the identity relation between object and dynamic in version 4.0 of the spec. 我将借用上面的参考转换示例,稍微调整一下,以说明规范4.0版本中objectdynamic之间的身份关系。

Let's say we have the types M<T> and N , and have defined somewhere the following implicit conversion: 假设我们有类型M<T>N ,并且在某处定义了以下隐式转换:

public static implicit operator M<object>(N n);

Then the following is legal: 那么以下是合法的:

N n = new N();
M<dynamic> m = n;

Clearly, the above is far less obvious than the two previous examples. 显然,上述内容远不如前两个例子明显 But here's the million-dollar question: would the above still be legal even if the excerpts from the spec quoted in the question did not exist? 但这是一个百万美元的问题: 即使问题中引用的规范摘录不存在,上述内容仍然合法吗? (I'm going to call these excerpts Q for brevity.) If the answer is yes, then Q is in fact redundant. (为简洁起见,我打算将这些摘录称为Q。 )如果答案是肯定的,那么Q实际上是多余的。 If no, then it is not. 如果不是,那就不是。

I believe the answer is yes. 我相信答案是肯定的。

Consider the definition of identity conversion , defined in section 6.1.1 (I am including the entire section here as it is quite short): 考虑6.1.1节中定义的身份转换的定义(我在这里包括整个部分,因为它很短):

An identity conversion converts from any type to the same type. 身份转换从任何类型转换为相同类型。 This conversion exists such that an entity that already has a required type can be said to be convertible to that type. 存在这种转换,使得已经具有所需类型的实体可以说可转换为该类型。

Because object and dynamic are considered equivalent there is an identity conversion between object and dynamic , and between constructed types that are the same when replacing all occurences of dynamic with object . 因为objectdynamic被认为是等价的,所以在objectdynamic之间存在身份转换, 并且在用object替换所有dynamic出现时构造的类型之间是相同的 [emphasis mine] [强调我的]

(This last part is also included in section 4.7, which defines the dynamic type.) (最后一部分也包含在4.7节中,它定义了dynamic类型。)

Now let's look at the code again. 现在让我们再看看代码。 In particular I'm interested in this one line: 特别是我对这一行感兴趣:

M<dynamic> m = n;

The legality of this statement (disregarding Q -- remember, the issue being discussed is the hypothetical legality of the above statement if Q did not exist), since M<T> and N are custom types, depends on the existence of a user-defined implicit conversion between N and M<dynamic> . 这句话的合法性(无视Q - 记住,正在讨论的问题是如果 Q 存在则上述陈述的假设合法性),因为M<T>N是自定义类型,取决于用户的存在 -定义NM<dynamic>之间的隐式转换。

There exists an implicit conversion from N to M<object> . 存在从NM<object>的隐式转换。 By the section of the spec quoted above, there is an identity conversion between M<object> and M<dynamic> . 根据上面引用的规范部分,在M<object>M<dynamic>之间存在身份转换。 By the definition of identity conversion , M<object> and M<dynamic> are the same type . 通过身份转换的定义, M<object>M<dynamic> 是相同的类型

So, just as in the first two (more obvious) examples, I believe it is true that an implicit conversion exists from N to M<dynamic> even without taking Q into account , just as it is true that an implicit conversion exists from N to K in the first example and that a boxing conversion exists from int to IComparable<System.Int32> in the second example. 因此,就像在前两个(更明显的)示例中一样,我认为即使不考虑Q存在从NM<dynamic>的隐式转换,就像从N存在隐式转换一样。在第一个示例中为K ,并且在第二个示例中,从intIComparable<System.Int32>存在装箱转换。

Without Q , this is much less obvious (hence Q 's existence); 没有Q ,这就不那么明显了(因此Q存在); but that does not make it false (ie, Q is not necessary for this behavior to be defined). 但这并不是假的 (即,定义此行为不需要 Q )。 It just makes it less obvious. 它只是使它不那么明显。

Conclusion 结论

I said in my original answer that this is the "obvious" explanation, because it seemed to me you were barking up the wrong tree. 我在原来的答案中说,这是“明显的”解释,因为在我看来,你正在吠叫错误的树。 You initially posed this challenge: 你最初提出了这个挑战:

Can you give an example of two types T 1 , T 2 such that T 1 would not be implicitly convertible to T 2 if it weren't for the above-quoted paragraphs? 你能给出一个T 1 ,T 2这两种类型的例子,如果不是上面引用的段落,T 1就不能隐式转换为T 2吗?

No one's going to meet this challenge, Timwi, because it's impossible. 没有人会遇到这个挑战,蒂姆维,因为这是不可能的。 Take the first excerpt about reference conversions. 参考有关参考转换的第一段摘录。 It is saying that a type K is implicitly convertible to a type T if it is implicitly convertible to T 0 and T 0 is the same as T. Deconstruct this, put it back together, and you're left with an obvious tautology: K is implicitly convertible to T if it's implicitly convertible to T. Does this introduce any new implicit conversions? 假设类型K可以隐式转换为类型T,如果它可以隐式转换为T 0并且T 0与T相同。解构它,将它重新组合在一起,并且你留下了明显的重言式:K如果它可以隐式转换为T,则可以隐式转换为T.这会引入任何新的隐式转换吗? Of course not. 当然不是。

So maybe Ben Voigt's comment was correct; 也许Ben Voigt的评论是正确的; maybe these points that you're asking about would've been better placed in footnotes, rather than in the body of the text. 也许你所询问的这些要点会更好地放在脚注中,而不是放在文本正文中。 In any case, it's clear to me that they are redundant, and so to start with the premise they cannot be redundant, or else they wouldn't be there is to embark on a fool's errand. 在任何情况下,我清楚它们多余的,因此从这个前提开始它们不能是多余的,否则它们就不会有傻瓜的差事。 Be willing to accept that a redundant statement may still shed some light on a concept that may not be obvious to everyone, and it will become easier to accept these statements for what they are. 愿意接受冗余的陈述可能仍然会对一个对每个人都不太明显的概念有所了解,并且接受这些陈述将变得更容易。

Redundant? 冗余? Yes. 是。 Tautologous? 同义反复? Yes. 是。 Pointless? 无意义? In my opinion, no. 看来,没有。

*Obviously, I did not have any part in writing the C# language specification. *显然,我没有参与编写C#语言规范。 If I did, this answer would be a lot more authoritative. 如果我这样做,这个答案会更具权威性。 As it is, it simply represents one guy's feeble attempt to make sense of a rather complex document. 事实上,它只是代表一个人试图理解一个相当复杂的文件的微弱尝试。


Original answer 原始答案

I think you're (perhaps intentionally) overlooking the most obvious answer here. 我认为你(或许有意)忽略了这里最明显的答案。

Consider these two sentences in your question: 在你的问题中考虑这两句话:

(1) Initially they seem redundant (tautologous). (1)最初它们似乎是多余的(同义词)。 (2) But they must be there for a purpose, so why are they there? (2)但他们必须在某个目的,所以为什么他们在那里?

To me, the implication of these two sentences together is that a tautologous statement serves no purpose. 对我来说,这两个句子的含义是一个同义词的说法没有任何意义。 But just because a statement follows logically from established premises, that does not make it obvious to everyone. 但是,仅仅因为声明遵循既定的前提逻辑,这并不是每个人都明白的。 In other words even if (1) is true, the answer to (2) may simply be: to make the described behavior clear to anyone reading the spec . 换句话说,即使(1)为真,对(2)的答案可能只是: 使所描述的行为对于阅读规范的任何人都清楚

Now you might argue that even if something is not obvious , it still does not belong in a specification if it is providing a redundant definition. 现在你可能会争辩说,即使某些东西不明显 ,如果提供冗余定义,它仍然不属于规范。 To this potential objection, I can only say: be realistic. 对于这种可能的反对意见,我只能说:做到现实。 It's not really practical (in my opinion) to comb through a document stripping out all statements which are simply stating facts that could have been deduced from prior statements. 在我看来,梳理一份文件,删除所有只是陈述可以从先前陈述中推断出的事实的陈述,这是不切实际的(在我看来)。

If this were a common practice, I think you'd find a lot of literature out there -- not just specs, but research papers, articles, textbooks, etc. -- would be a lot shorter, denser, and more difficult to understand. 如果这一种常见的做法,我认为你会发现很多文献 - 不只是规格,而是研究论文,文章,教科书等 - 会更短,更密集,更难理解。

So: yes, perhaps they are redundant. 所以:是的,也许它们是多余的。 But that does not negate their purpose. 但这并不能否定他们的目的。

Section 4.7 of the specification notes that there is an identity conversion from Foo<dynamic> to Foo<object> and vice versa. 规范的第4.7节指出存在从Foo<dynamic>Foo<object>的身份转换,反之亦然。 The portion of the spec you quoted is written to ensure that this case is handled. 您引用的规范部分是为了确保处理此案例而编写的。 That is, if there is an implicit reference conversion from T to C<object, object> then there is also an implicit reference conversion to C<object, dynamic> , C<dynamic, object> and C<dynamic, dynamic> . 也就是说,如果存在从T到C<object, object>的隐式引用转换,那么还存在对C<object, dynamic>C<dynamic, object>C<dynamic, dynamic>的隐式引用转换。

One might reasonably point out that (1) the intention of these phrases is unobvious - hence your question - and confusing, and (2) that the section on identity conversions ought to cross-reference the section on dynamic conversions, and (3) phrases like this in the spec make it difficult for an implementor of the specification to clearly translate the spec language into an implementation. 有人可能会合理地指出:(1)这些短语的意图并不明显 - 因此你的问题 - 并且令人困惑,(2)关于身份转换的部分应该交叉引用关于动态转换的部分,以及(3)短语像规范中的这样,规范的实现者很难将规范语言清楚地转换为实现。 How is one to know if any such type exists? 如何知道是否存在任何此类类型? The spec need not specify exact algorithms, but it would be nice if it gave more guidance. 规范不需要指定精确的算法,但如果它提供更多的指导,那将是很好的。

The spec is, sadly, not a perfect document. 遗憾的是,该规范并不是一份完美的文件。

An identity conversion converts from any type to the same type . 身份转换从任何类型转换为相同类型 This conversion exists such that an entity that already has a required type can be said to be convertible to that type. 存在这种转换, 使得已经具有所需类型的实体可以说可转换为该类型。

This says that in C#-land, 1==1; 这表示在C#-land中,1 == 1; a Spade is a Spade. 锹是一个锹。 This is the basis of assigning an object reference to a variable of the same type; 这是将对象引用分配给相同类型的变量的基础; if a variable typed T1 and one typed T2 are in reality both Spades, it is possible to assign one to the other without having to explicitly cast one as a Spade. 如果变量类型T1和一个类型T2实际上都是黑桃,则可以将一个分配给另一个,而不必将其中一个显式转换为Spade。 Imagine a C# variant where assignments had to look like this: 想象一下C#变体,其中赋值必须如下所示:

Spade mySpade = new Spade();
Spade mySpade2;

mySpade2 = (Spade)mySpade; //explicit cast required

Also, an "identity" in mathematics states that an expression that evaluates to a result given a set of inputs is equivalent to another expression that produces the same result given the same inputs. 此外,数学中的“同一性”表明,给定一组输入的结果的表达式等价于另一个表达式,该表达式在给定相同输入的情况下产生相同的结果。 In programming, this means that an expression or function that evaluates to an instance of a type is equivalent to that type, without explicit conversion. 在编程中,这意味着计算类型实例的表达式或函数等效于该类型,而不进行显式转换。 If that didn't hold, the following code would be required: 如果不成立,则需要以下代码:

public int myMethod() { /*Do something*/ }
...
int myInt = (int)myMethod(); //required even though myMethod() evals to an int.
...
int myInt = (int)(1 + 2); //required even though 1, 2, and 1+2 eval to an int.

The second rule basically says that a value type can be assigned to a member variable on a class if, in part, the member variable (a boxed type by definition, as its container is a reference type) is declared to be the same type. 第二个规则基本上表示可以将值类型分配给类上的成员变量,如果部分变量(按定义为盒装类型,因为其容器是引用类型)被声明为相同类型。 If this rule were not specified, theoretically, a version of C# could exist in which pure value types would have to be explicitly converted to their reference analog in order to be stored as a member variable on a class. 如果未指定此规则,理论上可能存在一个C#版本,其中纯值类型必须显式转换为其引用模拟,以便作为成员变量存储在类中。 Imagine, for example, a version of C# in which the blue keyword types (int, float, decimal) and the light blue class names (Int32, Float, Decimal) referred to two very different, only-explicitly-convertible types, and int, float, decimal etc. were not legal as member variable types because they were not reference types: 想象一下,例如,一个C#版本,其中blue关键字类型(int,float,decimal)和浅蓝色类名称(Int32,Float,Decimal)引用两个非常不同的,只能显式转换的类型,以及int ,float,decimal等作为成员变量类型不合法,因为它们不是引用类型:

public class MyClass
{
  Int32 MyBoxedValueType; //using "int" not legal
}

...

MyClass myClass = new MyClass();
int theInt = 2;

myClass.MyBoxedValueType = (Int32)theInt; //explicit cast required

I know it sounds silly, but at some level, these things must be known, and in computers, you have to specify EVERYTHING. 我知道这听起来很愚蠢,但在某种程度上,这些东西必须是已知的,而在计算机中,你必须指定一切。 Read the USA Hockey rulebook for ice hockey sometime; 有时读冰岛美国曲棍球规则手册; the very first rule in the book is that the game shall be played on an ice surface. 本书的第一条规则是游戏应该在冰面上进行。 It's one of the ultimate "well duhs", but also a fundamental truth of the game that must be understood in order for any other rule to make sense. 它是最终的“好战”之一,但也是必须理解的游戏的基本事实,以便任何其他规则有意义。

May it is such that the code guarantees pass-through when called like Convert.ChangeType(client, typeof(Client)) regardless if IConvertible is implemented. 可能是这样,代码在像Convert.ChangeType(client, typeof(Client))一样被调用时保证传递Convert.ChangeType(client, typeof(Client))无论是否实现了IConvertible

Look into the source of ChangeType from mscorlib with Reflector and notice the conditions at which value is returned as-is. 从带有Reflector的mscorlib查看ChangeType的源代码,并注意按原样返回value的条件。

Remember a = operator is not a conversion, just a reference set. 记住a =运算符不是转换,只是参考集。 So code like Client client_2 = client_1 does not perform any implicit conversions. 因此, Client client_2 = client_1类的代码不会执行任何隐式转换。 If an identity implicit conversion is declared then error CS0555 is issued. 如果声明了标识隐式转换,则发出错误CS0555

I guess the spec says let the C# compiler handle such cases, and thus dot not manually try to define identity conversions. 我想规范说让C#编译器处理这种情况,因此不要手动尝试定义身份转换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM