7

2 つのプロジェクトで Visual Studio 2010 を使用しています。

1 つには、ExchangeServices にアクセスするための Microsoft の Exchange.WebServices dll (ver1.2) を参照するプロジェクトが含まれています。Exchange サーバーに (ExchangeService API を介して) 接続しているときにさまざまなタスクを実行するためのヘルパー メソッドとラッパーを含むクラスを作成しました。ExchangeService コンストラクターは、サーバーのバージョン情報を指定するために、ExchangeVersion の列挙型を受け入れることができます。そこで、クラス内に 2 つのコンストラクターを作成しました。

public class ExchangeConnector(string ver)
{
    // Property assignments
}

public class ExchangeConnector(ExchangeVersion ver)
    :this(ver.toString()) //Using(or not using) "this", doesn't seem to matter...
{ }

他のプロジェクトが Exchange.WebServices ライブラリを追加する必要がないように、文字列パラメーターを受け入れるコンストラクターを作成しました。

しかし、その後、予期せぬ問題に遭遇しました。

2 番目のプロジェクト (Exchange.WebServices dll への参照を含まない) で ExchangeConnector("Exchange2007_SP1") のインスタンスを作成すると、Intellisense は適切なコンストラクターを選択せず​​、プリコンパイル エラーを表示しません。ただし、ビルドを強制すると、次のエラーが発生します。

Error: The type 'Microsoft.Exchange.WebServices.Data.ExchangeVersion' is defined
in an assembly that is not referenced. You must add a reference to assembly
'Microsoft.Exchange.WebServices, Version=14.0.0.0, Culture=neutral, 
PublicKeyToken=31bf3856ad364e35'.

私は ExchangeVersion 列挙参照でコンストラクターを使用していませんが、それへの参照が必要ですか?

ExchangeVersion 列挙型を使用してコンストラクターをコメント アウトすると、すべてがコンパイルされ、動作し、実行時エラーは発生しません。または、Intellisense が次のように 2 つを混同できないように、オーバーロード コンストラクターを変更した場合:

public class ExchangeConnector(string url, ExchangeVersion ver)
{ 
  // Property assignments
}

ExchangeConnector("Exchange2007_SP1") を呼び出すと、コードがコンパイルされ、正常に動作します。実行時エラーはありません。

VS が適切に使用するコンストラクターを解決できないかのようです。これで、2 番目のプロジェクトへの参照を追加して完了できることがわかりましたが、なぜ VS がこれを行っているのか興味があります。何か案は?

4

2 に答える 2

8

Scott (もう 1 人) からのインスピレーションと CodeCaster によって提供されたリンクの後、私は最終的に自分の答えを見つけたと思います。

これは、C# 言語仕様 (Visual Studio .Net 2003 Edition) の一部です。

セクション10.10インスタンス コンストラクター:

base(argument-listopt) 形式のインスタンス コンストラクター初期化子により、直接基底クラスからインスタンス コンストラクターが呼び出されます。そのコンストラクターは、引数リストとセクション 7.4.2 のオーバーロード解決規則を使用して選択されます。候補インスタンス コンストラクターのセットは、直接基底クラスに含まれるすべてのアクセス可能なインスタンス コンストラクター (セクション 10.10.4 で定義されている既定のコンストラクターを含む) で構成されます。このセットが空の場合、または単一の最適なインスタンス コンストラクターを識別できない場合、コンパイル時エラーが発生します。

定義をさらに掘り下げる...

セクション 7.4.2 過負荷の解決:

候補の関数メンバーと引数リストが識別されると、最適な関数メンバーの選択はすべての場合で同じになります。

  • 適用可能な候補関数メンバーのセットが与えられると、そのセット内の最適な関数メンバーが特定されます。
  • セットに関数メンバーが 1 つしか含まれていない場合、その関数メンバーが最適な関数メンバーです。
  • それ以外の場合、セクション 7.4.2.2 の規則を使用して各関数メンバーが他のすべての関数メンバーと比較される場合、最良の関数メンバーは、指定された引数リストに関して他のすべての関数メンバーよりも優れている 1 つの関数メンバーです。
  • 他のすべての関数メンバーよりも優れた関数メンバーが 1 つだけ存在しない場合、関数メンバーの呼び出しがあいまいになり、コンパイル時エラーが発生します。

そしてさらに...

セクション 7.4.2.2 より良い機能メンバー[3]

[3][http://msdn.microsoft.com/en-us/library/aa691338(v=vs.71).aspx]

引数の型のセット {A1, A2, ..., AN} を持つ引数リスト A と、パラメーターの型 {P1, P2, ..., PN} と {Q1, Q2, ..., QN} の場合、MP は MQ よりも優れた関数メンバーとして定義されます。

  • 各引数について、AX から PX への暗黙的な変換は、AX から QX への暗黙的な変換より悪くはありません。
  • 少なくとも 1 つの引数について、AX から PX への変換は、AX から QX への変換よりも優れています。

この評価を実行するときに、MP または MQ が展開された形式で適用できる場合、PX または QX はパラメーター リストの展開された形式のパラメーターを参照します。

要約すると

同じ数の引数を持つコンストラクターは、どの関数メンバー (コンストラクター) が優れているかについて、暗黙的な変換によって評価する必要があります。

したがって、コンパイラがどのコンストラクターが優れているかを判断できるように、2 番目のプロジェクトへの参照を追加する必要があったのはなぜですか。

コンストラクターの引数の数が同じでない場合、評価を行う必要はなく、コンパイラーは 2 番目のプロジェクトへの参照を必要としません。

于 2013-08-13T21:24:12.693 に答える
3

プロジェクトがオーバーロードされたコンストラクターを持つ別のプロジェクトを参照している場合、それらのコンストラクターの 1 つが参照されるライブラリを受け入れる場合、その特定のコンストラクターを使用していなくても、呼び出し元のプロジェクトがコンパイルするためにその参照が必要になることは私には理にかなっています。コンパイラは、使用するコンストラクタを決定するためにその参照を必要としませんか? 多分私は何かが欠けているかもしれませんが、それが正しく機能していることは論理的に思えます。

于 2013-08-09T15:34:11.077 に答える