質問

セクション 6.1 暗黙的な変換 を定義します ID変換 したがって:

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

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

(§6.1.6 暗黙的な参照変換において)

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

  • [...]
  • どれからでも 参照型参照型 T 暗黙的な ID または参照への変換がある場合、 参照型 T0 そして T0 へのアイデンティティ変換があります T.

そして:

(§6.1.7 ボクシング変換)

  • 値型にはインターフェイス型へのボックス変換があります。 I インターフェイス型へのボクシング変換がある場合 I0 そして I0 へのアイデンティティ変換があります I.

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

2つのタイプの例を教えてください T1, T2 そのような T1 するだろう ない 暗黙的に〜に変換可能である T2 上で引用した段落がなかったら?

役に立ちましたか?

解決

仕様のセクション4.7は、からのアイデンティティ変換があることに注意してください Foo<dynamic>Foo<object> およびその逆。引用した仕様の部分は、このケースが処理されるように書かれています。つまり、tからtへの暗黙の参照変換がある場合 C<object, object> 次に、暗黙の参照変換もあります C<object, dynamic>, C<dynamic, object>C<dynamic, dynamic>.

(1)これらのフレーズの意図は解放されていない - したがってあなたの質問であり、(2)アイデンティティ変換に関するセクションが動的変換のセクションを相互参照する必要があることを合理的に指摘するかもしれません。仕様のこのように、仕様の実装者がスペック言語を実装に明確に変換することを困難にします。そのようなタイプが存在するかどうかをどのように知ることができますか?仕様は正確なアルゴリズムを指定する必要はありませんが、より多くのガイダンスを与えた場合は素晴らしいことです。

スペックは、悲しいことに、完璧なドキュメントではありません。

他のヒント

2010 年 9 月 22 日の更新:

ティムウィ以外にこれを読む人はいないでしょう。それでも、新しい回答が受け入れられ、仕様の引用部分が引用されているかどうかについての議論が(少なくとも私の想像の世界では)まだ続いているという事実を考慮して、この回答にいくつかの編集を加えたいと思いました。技術的には冗長です。あまり追加することはありませんが、内容が多すぎてコメントに収まりません。アップデートの大部分は、次の見出しの下にあります。 「以下を含む変換 dynamic タイプ" 下に。


2010 年 9 月 19 日の更新:

コメントの中で:

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

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

免責事項:私は持っている 絶対にありません 仕様をできるだけ詳しく調べました。最近の質問のいくつかによると、最近この問題についてかなり詳しく調べているようです。これにより、SO のほとんどのユーザーよりも多くの詳細に自然に精通できるようになります。したがって、これは、エリック・リッパート以外の人から受け取る可能性が高いほとんどの回答と同様に、あなたを満足させないかもしれません。

異なる敷地

まず、あなたの質問の前提は、強調表示されているステートメントが次の場合です。 冗長な, 、その場合、彼らはサービスを提供しません 目的. 。私の回答の前提は、冗長な記述は、何かを明確にする場合には必ずしも目的がないわけではないということです。 誰にとっても明らかではありません. 。これらは矛盾した前提です。そして、前提条件で同意できない場合、単純な論理的な議論はできません。私はただ、前提を考え直してほしいとお願いしただけなのです。

しかし、あなたの答えは次のとおりでした。 繰り返す あなたの前提:「本当に冗長な文であれば、読者を混乱させるだけで、何も明確になりません。」

(ところで、私はあなたが自分自身を仕様のすべての読者の代表者として設定している方法が好きです。)

正確に言えば、あなたがこの立場を維持していることを責めることはできません。つまり、そうなります 思われる 明らか。そして、最初の回答では具体的な例を示しませんでした。そこで、以下に具体的な例をいくつか挙げてみたいと思います。しかし最初に、一歩下がって、なぜこの奇妙なことが起こったのかについて私の見解を述べさせてください。 ID変換 コンセプトはそもそも仕様の中に存在します。

の目的 ID変換 意味

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

これにより、本質的に推移的な変換に関するステートメントが可能になります。トートロジーステートメントの例として仕様から引用した最初の点は、このカテゴリに分類されます。ある型 (K と呼ぶことにします) に対して別の型 T への暗黙的な変換が定義されている場合、それは述べています。0 そしてT0 へのアイデンティティ変換があります T の場合、K は暗黙的に T に変換可能です。の定義によれば、 ID変換 上記では、「本当に「意味」へのアイデンティティ変換があります。声明はそうです 冗長な.

しかし、また次のようになります。の ID変換 定義は、仕様を記述するための形式的な言語を備えるために最初に存在します。 コンバージョン 「もしTなら」などと言う必要はありません。0 TさんとTさんは本当に同じタイプなんです。

さて、具体的な例を見てみましょう。

暗黙的な変換が存在する場合 かもしれない 明らかではない いくつかの 開発者

注記:あ ずっといい 例は Eric Lippert によって提供されています。 質問に対する彼の答え. 。最初の 2 つの例は、私の要点を少しだけ補強するものとして残しておきます。また、間に存在する ID 変換を具体化する 3 番目の例も追加しました。 object そして dynamic エリックの答えで指摘されているように。

推移的な基準変換

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;

さて、先に進む前に、次のことに気づきました。 これは明らかです あなた そして 自分. しかし、私の答えは、そして最初からそうである、です。 ない 明らかである みんな, したがって、それを指定します--一方 冗長な--まだあります 目的.

それ 目的 は:そのコードを見て頭を悩ませている人にはっきり言っておきますが、それは合法です。アン 暗黙的な変換 N から M まで存在し、 ID変換 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>, 、 と ID変換 から存在します IComparable<int>IComparable<System.Int32> (つまり、 IComparable<int> そして IComparable<System.Int32> 同じタイプです);したがって、ボクシングへの変換は intIComparable<System.Int32>.

を含む変換 dynamic タイプ

上記の参照変換例から借用し、わずかに調整して、次の相互関係を示します。 object そして dynamic 仕様のバージョン 4.0 では、

型があるとしましょう M<T> そして N, 、次の暗黙的な変換をどこかに定義しています。

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

その場合、次は合法です。

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

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

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

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

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

なぜなら object そして dynamic 同等であるとみなされます。間に同一性変換が存在します。 object そして dynamic, および、出現するすべての文字列を置き換える場合に同じである構築型間 dynamicobject. [私のことを強調]

(この最後の部分は、セクション 4.7 にも含まれており、 dynamic タイプ。)

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

M<dynamic> m = n;

この声明の合法性(無視 Q -- 覚えておいてください、議論されている問題は上記の声明の仮説上の合法性です もし Q した ない 存在します)、以来 M<T> そして N カスタム型であり、ユーザー定義による暗黙的な変換の存在に依存します。 N そして M<dynamic>.

からの暗黙的な変換が存在します。 NM<object>. 。上記で引用した仕様のセクションにより、次の間でアイデンティティ変換が行われます。 M<object> そして M<dynamic>. 。の定義によれば、 ID変換, M<object> そして M<dynamic> 同じタイプです.

したがって、最初の 2 つの (より明白な) 例と同様に、暗黙的な変換が存在することは真実だと思います。 NM<dynamic> 取らなくても Q 考慮に入れて, からの暗黙的な変換が存在するのと同じように、 NK 最初の例では、ボクシング変換が存在します。 intIComparable<System.Int32> 2番目の例では。

それなし Q, 、これはあまり明らかではありません(したがって、 Qの存在); しかし、だからといってそれが間違っているわけではありません (つまり、 Q ではありません 必要 この動作を定義するには)。それはそれを目立たなくするだけです。

結論

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

2 つのタイプ T の例を挙げていただけますか1, 、T2 Tが1 暗黙的に T に変換できません2 上で引用した段落がなかったら?

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

したがって、Ben Voigt のコメントは正しかったのかもしれません。あなたが質問しているこれらの点は、本文ではなく脚注に配置した方が良かったのかもしれません。いずれにしても、彼らが 冗長なので前提から始めます 冗長にすることはできません。そうでない場合は存在しません。 愚かな用事を始めることだ。冗長な記述であっても、誰にとっても明らかではない概念に何らかの光を当てる可能性があることを喜んで受け入れてください。そうすれば、これらの記述をありのままに受け入れることが容易になります。

冗長ですか?はい。トートロジー?はい。無意味ですか?で 私の 意見、いいえ。

*明らかに、私は C# 言語仕様の作成には一切関与していません。もしそうなら、この答えはより信頼できるものになるでしょう。実際のところ、これは、かなり複雑な文書を理解しようとする一人の男の弱い試みを表しているだけです。


元の回答

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

質問内の次の 2 つの文を考えてみましょう。

(1) 当初、それらは冗長に見えます(張会)。 (2) しかし、彼らは目的のためにそこにいなければならないので、なぜ彼らはそこにいるのでしょうか?

私にとって、これら 2 つの文が一緒になって意味するのは、トートローグなステートメントは何の役にも立たないということです。しかし、あるステートメントが確立された前提に論理的に従っているからといって、それが誰にとっても明らかであるとは限りません。つまり、たとえ、 (1) は本当です、に対する答えは (2) 単純に次のようになります: 仕様を読んでいる人に説明されている動作を明確にするため.

さて、たとえ何かがそうでなかったとしても、あなたはこう主張するかもしれません 明らか, 、冗長な定義を提供している場合でも、仕様には属しません。この潜在的な反対意見に対して、私は次のようにしか言えません。現実的になること。(私の意見では) 文書をくまなく調べて、以前の陳述から推測できる事実を単に述べているだけの陳述をすべて取り除くことは、実際には現実的ではありません。

これなら だった よくあることですが、仕様書だけでなく、研究論文、記事、教科書など、たくさんの文献が見つかると思います。-- はるかに短く、密度が高く、理解するのが難しくなります。

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

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

これは、C#-land、1 == 1であると書かれています。スペードはスペードです。これは、同じタイプの変数にオブジェクト参照を割り当てる基礎です。可変タイプT1とタイプされたT2とタイプされた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、小数)が2つの非常に異なる、唯一の唯一の範囲で変換可能なタイプ、およびintを参照したC#のバージョンを想像してください。 、フロート、小数などは、参照タイプではなかったため、メンバー変数タイプとして合法ではありませんでした。

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

...

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

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

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

次のように呼ばれると、コードがパススルーを保証するようなものですように Convert.ChangeType(client, typeof(Client)) 関係なく IConvertible 実装されています。

のソースを調べてください ChangeType から mscorlib リフレクターで、その条件に気づきます value そのまま返されます。

覚えておいてください = オペレーターは変換ではなく、参照セットだけです。だからコードのような Client client_2 = client_1 暗黙の変換は実行されません。アイデンティティ暗黙の変換が宣言された場合、エラー CS0555 発行されます。

スペックには、C#コンパイラがそのようなケースを処理させると言っていると思います。 ドットではありません アイデンティティ変換を手動で定義してみてください。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top