11

セクション 6.1 Implicit conversionsでは、恒等変換を次のように定義しています。

ID 変換は、任意の型から同じ型に変換します。この変換は、必要な型を既に持っているエンティティがその型に変換可能であると言えるように存在します。

では、このような文の目的は何でしょうか?

(§6.1.6 暗黙の参照変換で)

暗黙の参照変換は次のとおりです。

  • [...]
  • 任意の参照型から参照 T型への暗黙的な ID または参照 T0への参照変換があり、T0に への ID 変換がある場合T

と:

(§6.1.7 ボクシング変換で)

  • 値型は、インターフェイス型0Iへのボックス化変換があり、0 が への ID 変換を持っている場合、インターフェイス型へのボックス化変換を持ちます。III

最初は冗長に見えます (トートロガス)。しかし、彼らは目的のためにそこにいるに違いないのに、なぜ彼らはそこにいるのでしょうか?

上記の段落がなければ、 1が暗黙的に2に変換できないような2 つのタイプT1T2の例を挙げていただけますか?TT

4

4 に答える 4

6

2010 年 9 月 22 日の更新:

ティムウィ以外にこれを読む人はいないだろう。それでも、新しい回答が受け入れられ、仕様の引用された抜粋が技術的に冗長です。私は多くを追加していませんが、コメントに収まるにはあまりにも重要です. 更新の大部分は、以下の「型を含む変換」dynamicという見出しの下にあります。


2010 年 9 月 19 日の更新:

あなたのコメントで:

[T]これは意味がありません。

くそー、ティムウィ、あなたはそれをたくさん言います。でも大丈夫です。あなたは私を守備に置いたので、ここに行きます!

免責事項:私は間違いなく、あなたほど詳細に仕様を調べていません. あなたの最近の質問のいくつかに基づいて、あなたは最近それをかなり調べているようです. これにより、SO のほとんどのユーザーよりも多くの詳細に慣れることができます。したがって、これは、Eric Lippert 以外から受け取る可能性が高いほとんどの回答と同様に、満足できない場合があります。

別の施設

まず、あなたの質問の前提は、強調表示されたステートメントが冗長である場合、それらは何の役にも立たないということです。私の回答の前提は、冗長なステートメントが、誰にとっても明らかではない何かを明確にする場合、必ずしも目的がないわけではないということです。これらは相反する前提です。そして、前提に同意できない場合、単純な論理的議論はできません。私はただ、あなたの前提を再考するようにお願いしただけです。

しかし、あなたの回答は、あなたの前提を繰り返すことでした。「文が本当に冗長である場合、それらは読者を混乱させるだけで、何も明確にしません。」

(ちなみに、仕様のすべての読者の代表として自分を設定した方法が気に入っています。)

あなたがこのポジションを保持していることを責めることはできません。つまり、それは明らかなようです。また、元の回答では具体的な例を挙げていませんでした。そこで、以下に具体的な例をいくつか含めてみます。しかし、最初に、一歩下がって、なぜこの奇妙なID 変換の概念が仕様に存在するのかについて、私の見解を述べさせてください。

恒等変換定義の目的

一見すると、この定義は不必要に思えます。任意の型 T のインスタンスが ... まあ、T に変換可能であると言っているだけではありませんか? はい、そうです。しかし、この定義の目的は、変換を議論するコンテキストで型同一性の概念を利用するための適切な語彙を仕様に提供することであると私は仮定します* 。

これにより、本質的に推移的な変換に関するステートメントが可能になります。トートロジーステートメントの例として仕様から引用した最初のポイントは、このカテゴリに分類されます。ある型 (K と呼びます) から別の型 T 0への暗黙の変換が定義されていて、T 0 が T への恒等変換を持つ場合、K は暗黙的に T に変換可能であるということです。与えられた恒等変換の定義により、上記の「同一の型に変換されている」は、実際には「と同じ型である」ことを意味します。したがって、ステートメントは冗長です。

繰り返しになりますが、恒等変換の定義は、「T 0と T が本当に同じ型である場合」などのことを言わなくても、変換を記述するための正式な言語を仕様に装備するために最初に存在します。

では、具体例の時間です。

一部の開発者にとって、暗黙的な変換の存在が明らかでない可能性がある場合

注: Eric Lippertの質問への回答で、はるかに優れた例が提供されています。これらの最初の 2 つの例は、私の要点を補強するためのものとして残しておきます。エリックの回答で指摘されているように、との間に存在する ID 変換を具体化する 3 番目の例も追加しました。objectdynamic

推移参照変換

と の 2 つの型がMありN、次のように定義された暗黙の変換があるとします。

public static implicit operator M(N n);

次に、次のようなコードを記述できます。

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

usingここで、次のステートメントが先頭にあるファイルがあるとします。

using K = M;

そして、ファイルの後半に次のものがあります。

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

OK、先に進む前に、これはあなたにもにも明らかなことだと思います。しかし、私の答えは、それは誰にとっても明らかではないかもしれないということであり最初からそうでした.

その目的は、そのコードを見て頭を悩ませている人に、それが合法であることを明確にすることです。N から Mへの暗黙的な変換が存在し、M から K への恒等変換が存在します (つまり、M と K は同じ型です)。したがって、N から K への暗黙の変換が存在します。これは単なる論理的なものではありません (論理的な場合もありますが)。それは仕様にあります。そうしないと、次のようなものが必要になると誤って信じるかもしれません。

K k = (M)n;

明らかに、そうではありません。

推移的なボクシング変換

または型を取りintます。はintとしてボックス化できますIComparable<int>よね?したがって、これは合法です:

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

これを考慮してください:

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

繰り返しますが、そうです、あなた、私、そしてこれに出くわす可能性のあるすべての開発者の 90% にとっては明白かもしれません。しかし、すぐにそれを見ないスリムな少数派の場合: から へのボクシング変換が存在し、 からintIComparable<int>同一性変換が存在IComparable<int>しますIComparable<System.Int32>(つまり、IComparable<int>IComparable<System.Int32>は同じ型です)。intそのため、 からへのボクシング変換が存在しIComparable<System.Int32>ます。

dynamic型を含む変換

上記の参照変換の例から借用し、仕様のバージョン 4.0 でのobjectとの同一関係を説明するために少し調整します。dynamic

M<T>型とNがあり、次の暗黙の変換をどこかに定義したとしましょう。

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

次に、以下が合法です。

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

明らかに、上記は前の 2 つの例よりもはるかに明白ではありません。しかし、ここに百万ドルの質問があります: 質問で引用された仕様からの抜粋が存在しなくても、上記は依然として合法でしょうか? (簡潔にするために、これらの抜粋をQと呼びます。) 答えが「はい」の場合、Qは実際には冗長です。いいえの場合、そうではありません。

答えはイエスだと思います。

セクション 6.1.1 で定義されている ID 変換の定義を考えてみましょう(非常に短いため、セクション全体をここに含めます)。

ID 変換は、任意の型から同じ型に変換します。この変換は、必要な型を既に持っているエンティティがその型に変換可能であると言えるように存在します。

objectとは同等であると見なされるため、 と の間、および のすべての発生を置き換えると同じである構築された型の間でdynamic同一性変換が行われます。[鉱山を強調]objectdynamicdynamicobject

(この最後の部分は、タイプを定義するセクション 4.7 にも含まれていますdynamic。)

では、もう一度コードを見てみましょう。特に、次の 1 行に興味があります。

M<dynamic> m = n;

とはカスタム型であるため、このステートメントの正当性は ( Qを無視します -- 議論されている問題は、Qが存在しない場合 の上記のステートメントの仮説上の正当性であることに注意してください)、との間のユーザー定義の暗黙的な変換の存在に依存します。.M<T>NNM<dynamic>

Nからへの暗黙の変換が存在しM<object>ます。上記の仕様のセクションでは、 と の間に恒等変換がM<object>ありM<dynamic>ます。恒等変換の定義により、M<object>M<dynamic> は同じ型です。

したがって、最初の 2 つの (より明白な) 例と同様に、 Q を考慮せずに から への暗黙的な変換が存在すること正しい思いNます。2 番目の例では、からへのボックス化変換が存在します。M<dynamic> NKintIComparable<System.Int32>

Qがなければ、これはあまり明白ではありません (したがって、Qの存在)。しかし、それは偽にはなりません(つまり、この動作を定義するためにQ必要ありません)。目立たなくするだけです。

結論

元の回答で、これは「明白な」説明だと言いました。なぜなら、あなたは間違った木を吠えているように思えたからです。あなたは最初にこの課題を提起しました:

上で引用したパラグラフがなければ、 T 1が暗黙的に T 2に変換できないような 2 つの型 T 1、 T 2の例を挙げていただけますか?

ティムウィ、誰もこの挑戦に立ち向かわないだろう、それは不可能だからだ。参照変換に関する最初の抜粋を見てみましょう。型 K が T 0に暗黙的に変換可能であり、T 0が T と同じ場合、型 K は型 T に暗黙的に変換可能であると言っています。これを分解し、元に戻すと、明らかなトートロジーが残ります: K暗黙的に T に変換可能な場合、暗黙的に T に変換可能です。これにより、新しい暗黙的な変換が導入されますか? もちろん違います。

したがって、おそらく Ben Voigt のコメントは正しかったでしょう。あなたが尋ねているこれらのポイントは、テキストの本文ではなく、脚注に配置する方が適切だったかもしれません. いずれにせよ、それらが冗長であることは明らかであり、前提から始めると、冗長になることはありません。冗長なステートメントが、誰にとっても明らかではないかもしれない概念に光を当てる可能性があることを喜んで受け入れてください。そうすれば、これらのステートメントが何であるかを受け入れやすくなります。

冗長?はい。互変異性?はい。無意味?私の意見では、いいえ。

*明らかに、私は C# 言語仕様の作成に関与していません。もしそうなら、この答えはもっと権威のあるものになるでしょう。現状では、かなり複雑な文書を理解しようとする一人の人間の弱々しい試みを表しているにすぎません。


元の答え

ここで最も明白な答えを見落としていると思います(おそらく意図的に)。

質問の次の 2 つの文を検討してください。

(1)最初は重複しているように見えます (トートロガス)。(2)しかし、それらは目的のためにそこにあるに違いありません。

私にとって、これら 2 つの文を一緒にすると、同義語のステートメントは何の役にも立たないということになります。しかし、ステートメントが確立された前提から論理的に従うからといって、それが誰にとっても明らかであるとは限りません. 言い換えれば、(1)が正しいとしても、 (2)に対する答えは単に:記述された動作を仕様を読んでいる人に明確にするためです。

ここで、何かが明白でなくても、冗長な定義を提供している場合、それは仕様に属さないと主張するかもしれません。この潜在的な反論に対して、私が言えることは、現実的であることだけです。以前の声明から推測できた可能性のある事実を単に述べているだけのすべての声明を除外してドキュメントをくまなく調べることは、(私の意見では)実際には実際的ではありません。

もしこれ一般的な慣習であったなら、仕様だけでなく、研究論文、記事、教科書などの多くの文献がそこにあると思います.はるかに短く、密度が高く、理解するのがより困難になるでしょう. .

だから:はい、おそらくそれらは冗長です。しかし、それは彼らの目的を否定するものではありません。

于 2010-09-17T18:07:10.793 に答える
2

Foo<dynamic>仕様のセクション 4.7 では、 からへFoo<object>、およびその逆の ID 変換があることに注意してください。引用した仕様の部分は、このケースが確実に処理されるように書かれています。つまり、 T から への暗黙的な参照変換がある場合、 、およびC<object, object>への暗黙的な参照変換も存在します。C<object, dynamic>C<dynamic, object>C<dynamic, dynamic>

(1) これらのフレーズの意図は自明ではないため、あなたの質問は紛らわしく、(2) 恒等変換に関するセクションは動的変換に関するセクションを相互参照する必要があること、および (3) フレーズこのような仕様では、仕様の実装者が仕様言語を実装に明確に翻訳することが困難になります。そのようなタイプが存在するかどうかをどのように知ることができますか? 仕様で正確なアルゴリズムを指定する必要はありませんが、より多くのガイダンスが提供されるとよいでしょう。

残念ながら、仕様は完全なドキュメントではありません。

于 2010-09-20T04:46:11.353 に答える
1

ID変換は、任意のタイプから同じタイプに変換されます。この変換は、すでに必要なタイプを持っているエンティティがそのタイプに変換可能であると言えるように存在します。

これは、C#ランドでは、1==1であることを示しています。スペードはスペードです。これは、同じタイプの変数にオブジェクト参照を割り当てるための基礎です。変数タイプのT1と1つのタイプのT2が実際には両方のスペードである場合、一方をスペードとして明示的にキャストしなくても、一方を他方に割り当てることができます。割り当てが次のようになっているC#バリアントを想像してみてください。

Spade mySpade = new Spade();
Spade mySpade2;

mySpade2 = (Spade)mySpade; //explicit cast 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.

2番目のルールは、基本的に、メンバー変数(そのコンテナーは参照型であるため、定義上、ボックス化された型)が同じ型であると宣言されている場合、値型をクラスのメンバー変数に割り当てることができることを示しています。このルールが指定されていない場合、理論的には、純粋な値型をクラスのメンバー変数として格納するために参照アナログに明示的に変換する必要があるバージョンのC#が存在する可能性があります。たとえば、青のキーワード型(int、float、decimal)と水色のクラス名(Int32、Float、Decimal)が2つの非常に異なる、明示的に変換可能な型、およびintを参照しているバージョンのC#を想像してみてください。 、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

ばかげているように聞こえますが、あるレベルでは、これらのことを知っている必要があり、コンピューターでは、すべてを指定する必要があります。いつかアイスホッケーのUSAホッケールールブックを読んでください。この本の最初のルールは、ゲームは氷の表面でプレイすることです。これは究極の「まあまあ」の1つですが、他のルールを理解するために理解する必要のあるゲームの基本的な真実でもあります。

于 2010-09-17T16:44:41.350 に答える
-1

Convert.ChangeType(client, typeof(Client))が実装されているかどうかに関係なく、コードが呼び出されたときにパススルーを保証するようなものである可能IConvertible性があります。

ChangeTypefrom mscorlibwith Reflectorのソースを調べて、valueがそのまま返される条件に注目してください。

=演算子は変換ではなく、単なる参照セットであることを忘れないでください。したがって、code likeClient client_2 = client_1は暗黙的な変換を実行しません。ID の暗黙的な変換が宣言されている場合は、エラーCS0555が発生します。

仕様では、C#コンパイラにそのようなケースを処理させるように指示していると思います。そのため、ドットは手動でID変換を定義しようとしません。

于 2010-09-19T05:24:29.110 に答える