C#でパラメーターをGuid.Emptyにデフォルト設定するにはどうすればよいですか?


178

私は言いたい:

public void Problem(Guid optional = Guid.Empty)
{
}

しかし、コンパイラは、Guid.Emptyがコンパイル時定数ではないと不平を言っています。

私は使用できないAPIを変更したくないので:

 Nullable<Guid>


切り替えの何が問題になっているNullable<Guid> optional = null(、より簡潔かGuid? optional = null)?現在それに渡されているすべてのGUIDは、コードの変更をまったく必要とせずに強制されます。
NH。

回答:


235

解決

new Guid()代わりに使用できます

public void Problem(Guid optional = new Guid())
{
  // when called without parameters this will be true
  var guidIsEmpty = optional == Guid.Empty;
}

あなたも使うことができます default(Guid)

default(Guid)も正確に動作しnew Guid()ます。

Guidは参照型でdefault(Guid)はなく値型であるため、nullたとえば、とは等しくありません。代わりに、デフォルトコンストラクターを呼び出すことと同じです。

つまり、これは:

public void Problem(Guid optional = default(Guid))
{
  // when called without parameters this will be true
  var guidIsEmpty = optional == Guid.Empty;
}

元の例とまったく同じです。

説明

なぜうまくいかなかったのGuid.Emptyですか?

エラーが発生する理由は、Emptyが次のように定義されているためです。

public static readonly Guid Empty;

したがって、それは定数ではなく変数です(として定義されてstatic readonlyいませんconst)。コンパイラーは、コンパイラー既知の値のみをメソッド・パラメーターのデフォルト値として持つことができます(ランタイムのみ既知ではありません)。

根本的な原因は、たとえばとは異なり、constを1つも持つことができないことです。試してもコンパイルできません。structenum

もう一度言うと、それはstructプリミティブ型ではありません。
.NETのすべてのプリミティブ型のリストについては、http: //msdn.microsoft.com/en-gb/library/system.typecode.aspxを参照してください
enum通常int、プリミティブであるを継承することに注意してください

しかしnew Guid()、定数でもありません!

定数が必要だと言っているのではありません。コンパイル時に決定できるものが必要です。Emptyはフィールドであるため、その値はコンパイル時には不明です(実行時のごく初期のみ)。

デフォルトのパラメータ値は、いてもよく、コンパイル時に知られなければならない const値、または何かのように、コンパイル時に既知の値になりますC#の機能を使用して定義されたdefault(Guid)new Guid()のコンパイル時に決定されている(structあなたが変更することはできませんとしてS structでコンストラクタをコード)。

defaultまたはをnew簡単に提供できますが、を提供することはできませんconst(これはプリミティブタイプまたはenum上記で説明したのでないため)。したがって、ここでも、オプションのパラメーター自体に定数が必要であると言っているわけではありませんが、コンパイラーの既知の値です。


5
まあ、それは通常の定数式を必要としません- new Guid()例えば定数式ではありません。C#の仕様定義は非常に明確に、許可されているものを含むが、定数に限定されません。(ただ、明確にし、それが効果的である C#スペック面でだけではない「定数式」、コンパイル時の定数)。
Jon Skeet、2011

3
返信の「説明」の部分を読んでください。この部分に答えるために追加されました。
Meligy 2011

いい説明ありがとうございます!
ダリル

default現在のみ使用できます:)
Joshit

151

Guid.Emptyはと同等でnew Guid()、はと同等default(Guid)です。だからあなたは使うことができます:

public void Problem(Guid optional = default(Guid))

または

public void Problem(Guid optional = new Guid())

このnew Foo()値は、次の場合にのみ適用されることに注意してください。

  • あなたは本当にパラメータレスコンストラクタを呼び出しています
  • Foo 値タイプです

言い換えると、コンパイラがそれを知っている場合、それは実際にはタイプのデフォルト値にすぎません:)

(興味深いことに、99.9%は、作成したカスタムコンストラクターを呼び出さないと確信してますnew Foo()。そのようなコンストラクターをC#の値型で作成することできませんが、IL では作成できます。)

このdefault(Foo)オプションはどのタイプに使用できます。


コンパイラエラーメッセージでこれが通知されないのはなぜですか、コンパイラはGuid.Emptyのケースをチェックして、より役立つメッセージを表示できます。
イアンリングローズ

4
@Ian Ringrose:正直に言うと、コンパイラーはタイプ固有のメッセージを一般的に持つべきではないと思います。
ジョンスキート、2011

2
パラメータをデフォルトの新しいオブジェクトに設定すると、PHPでメソッドが呼び出されるたびに新しいオブジェクトが作成されます。ただし、Pythonでプログラム全体のオブジェクトを1つだけ作成します。本当に、私はこれをPythonの数少ない設計上の欠陥の 1つと考えています。C#(およびVB.Net)がデフォルトのパラメーターで新しいオブジェクトを単に許可しないことでこの問題を回避できたのはうれしいです。ただし、この機能がPHPで本当に優れている場合もあります。
BlueRaja-Danny Pflughoeft、2011

1
これと同じことがASP.NET MVCコントローラーアクションで機能しない理由は何ですか?他のすべてのオプションのパラメーターは機能しますが(int、string)、GUIDでは機能しません。「 '/'アプリケーションでサーバーエラーが発生しました。パラメーターディクショナリには、null不可の型 'System.Guidのパラメーター' categoryId 'のnullエントリが含まれています'.. "コードは両方の仕様(default(Guid)およびnew Guid())で正常にコンパイルされますが、このエラーが発行されます。
mare

@mare:わからない、怖い。別のオプションはNullable<Guid>、潜在的にを使用することです。
Jon Skeet、2012年

18

使用できません:

default ( Guid )


1
特許 Operator '??' cannot be applied to operands of type 'System.Guid' and 'System.Guid'
再帰

4
すみません、私はそうではありませんでしたか?演算子として、しかし強調された疑問符として-私は編集します!
Nick

9

受け入れられた回答はASP.NET MVCでは機能せず、この実行時エラーが発生します。

[ArgumentException: The parameters dictionary contains a null entry for parameter 'optional' of non-nullable type 'System.Guid' for method 'System.Web.Mvc.ActionResult Problem(System.Guid)' ....

代わりに、以下を実行できます。

public void Problem(Guid? optional)
{
    if (optional == null)
    {
        optional = new Guid();
    }
}

反対投票の理由がわかります。質問では、APIを変更してNullable <Guid>を使用することはできません-十分公正
Majix

空のGuid値を使用してパラメーター "optional"を明示的に割り当てない限り、これはタイプGuidのオプションパラメーターを定義する最も自然な方法だと思います。
ゴンザロメンデス

4

コンパイラは完全に正しいです。Guid.Emptyはコンパイル時の定数ではありません。次のようにメソッドをオーバーロードしてみることができます:

public void Problem()
{
    Problem(Guid.Empty);
}

私はAPIを変更したくないと言った、私が飼いならそうとしているメソッドは10のパラメーターを超えています!
Ian Ringrose

@Ian Ringrose、私Guid x = default(Guid)は解決策として同意しますが、別の関数オーバーロードを追加しても、オプションの引数を追加するだけでAPIが複雑になることはありません。とにかく、それはオプションの引数が実際に行うことです。
tenfour

@ tenfour、10個のオプションのパラメーターと同じことを行うには、多くの新しい関数オーバーロードが必要になります!
Ian Ringrose 2011

10個を超えるパラメーターを必要とするパブリック関数がある場合、単一の引数をオプションにすることは実際には修正ではありません...また、元の質問を振り返ってみると、「 API」(tenfourが指摘するように、明示的なオーバーロードとオプションの引数の違いは実際には最小限です)が、パラメーターリストがその種のモンスターであるという質問には言及されていません。
CVn 2011

実際、これは問題に対する完全な答えです。
2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.