5

lib1.dllアセンブリにClass1.GetChild<T>() where T : DependencyObject拡張メソッドを作成しました。その後、lib1.dllに依存するすべてのアセンブリが次のエラーでコンパイルに失敗しました。

タイプ 'System.Windows.DependencyObject' は、参照されていないアセンブリで定義されています。アセンブリ「WindowsBase」などへの参照を追加する必要があります...

依存アセンブリがWindowsBaseを使用しない場合でも、WindowsBaseGetChildが必要なのはなぜですか?

.

再現するには (vs2010 .net4):

lib1.dll ( WindowsBaseを参照)

namespace lib1
{
    public static class Class1
    {
        public static T GetChild<T>(this DependencyObject src) where T : DependencyObject
        {
            return default(T);
        }
    }

    public static class Class2
    {
        public static int SomeExtMethod(this string src)
        {
            return 0;
        }
    }
}

lib2.dll ( lib1 を参照しますが、 WindowsBaseは参照しません)

using lib1;
class someClass
{
    void someFct()
    {
        "foo".SomeExtMethod(); // error: The type 'System.Windows.DependencyObject'
                // is defined in an assemebly that is not referenced. 
                // You must add a reference to assembly 'WindowsBase' etc..
    }
}

.

アップデート:

ジェネリック メソッドと拡張メソッドを混在させると、必ず何かがあると思います。次のサンプルで問題を実証しようとしました。

// lib0.dll
namespace lib0
{
    public class Class0 { }
}

// lib1.dll
using lib0;
namespace lib1
{
    public static class Class1
    {
        public static void methodA<T>() where T : Class0 { }    // A
        public static void methodB(Class0 e) { }                // B
        public static void methodC(this int src) { }            // C
    }

    public static class Class2
    {
        public static void methodD(this String s) { }
    }
}

// lib2.dll
using lib1;
class someClass
{
    void someFct()
    {
        Class2.methodD("");  // always compile successfully
        "".methodD();        // raise the 'must add reference to lib0' error depending on config. see details below.
    }
}

A, //B, //C->コンパイルOK

A, B, //C->コンパイルOK

//A, B, C->コンパイルOK

A, //B, C-> エラーを上げる

A, B, C-> エラーを上げる

//A意味methodAがコメントされています。Damien が指摘したように、型推論は何らかの役割を果たす可能性があります。内外を知りたいと思っています。

4

6 に答える 6

3

あなたの状況は、Microsoft からここで回答されています: https://connect.microsoft.com/VisualStudio/feedback/details/668498/problem-with-extension-method-in-c-compiler

このエラーを誤って生成する拡張メソッドとは関係なく、他のユースケースもあります。

このことを考慮:

  1. ライブラリー (LB1 など) で定義されたタイプ (TP1 など) で汎用メソッドを定義します。
  2. 型は、他のライブラリ LB2 で定義された型のジェネリック メソッドを制約します。
  3. TP1に別のメソッドを定義してください。
  4. ライブラリで LB1 のみを参照し、タイプ TP1 の 2 番目のメソッドを呼び出してみます。

TP1 を使用せず、LB1 で定義されている他のタイプを使用すると、エラーは発生しません。また、タイプ TP1 のメソッドの 1 つが LB2 で定義されたタイプのパラメーターを期待している場合でも (そして、このメソッドを呼び出さなくても)、このエラーは発生しません。

于 2012-09-28T14:04:23.567 に答える
2

あるアセンブリが別のアセンブリに依存している場合、最初のアセンブリは、使用されているものに関係なく、他のアセンブリのすべての依存関係にも依存します。アセンブリの依存関係は効果的に分離され、コンパイル後にいずれかのアセンブリの別のバージョンを配置できます。コンパイラは、このような状況では、2 番目のアセンブリの 1 つ以上の依存関係が最初のアセンブリで使用されないことを認識できません。

この問題を解決するには、WindowsBase への参照を追加するだけです。

または、prashanth が指摘するようSomeExtMethodに、別のアセンブリに入れて、それを使用するコードが WindowsBase に依存する必要がないようにします。

更新: アセンブリから何も使用しない場合、その依存関係は必要ありません。ただし、1 つのアセンブリを使用するとすぐに、そのアセンブリのすべての依存関係も必要になります。これは、Visual Studio が参照を追加する方法で明らかです。アセンブリへの参照を追加すると、すべての依存アセンブリ (GAC に登録されていない) が、追加したアセンブリと共にデバッグ/リリース ディレクトリにコピーされます。

更新: コンパイル エラーについて: それが書かれた方法です。他に理由はないかもしれません。依存アセンブリを参照しない場合にコンパイル エラーが発生するのは良い考えですか? おそらく、参照から何かを使用する可能性が高く、参照参照から直接何かを使用する可能性があります-展開エラーよりもコンパイルエラーの方が適切です。

参照されていないすべての二次依存関係でコンパイル エラーが発生しないのはなぜですか? 繰り返しますが、そのように書かれていました。ここでもエラーが発生する可能性があります。しかし、それは重大な変更であり、本当に説得力のある理由が必要です。

于 2012-09-21T15:46:45.470 に答える
0

コンパイラチームの誰か以外の誰かがこれに答えられるかどうかはわかりません。私は今、それが型推論に関係していると考えています-しかし、§7.6.5.1メソッドの呼び出しは推論について話しますが、§7.6.5.2拡張メソッドの呼び出しは問題について沈黙しています-推論が検索時に明らかに行われるという事実にもかかわらず該当する拡張方法。

識別子の比較を実行する前に、何らかの形の推論を試みていると思います(名前が間違っているため、拡張メソッドがすぐに除外されます)。明らかに、タイプの制約を理解できない場合、このタイプに対していかなる形式の推論も実行できません。

したがって、型制約をちょうどclassに変更すると、このメソッドを正常に渡すようになります。型パラメーターを推測できますが、この拡張メソッドを正常に削除するようになりました。

于 2012-09-21T14:01:44.750 に答える
0

別のアセンブリを参照する場合、コンパイラはそのアセンブリで定義されているメソッドシグネチャを解析できる必要があると思います。そのため、コンパイラは、その関数の呼び出しを検出した場合に、その関数を見つける場所を認識しています。

GetChild()関数を次のように置き換える場合

    public static T GetChild<T>(this T src)
    {
        if (typeof(T) == typeof(DependencyObject)) return default(T);
        else return default(T);
    }

またはそれに類似したもので、実行しているWindowsBaseへの参照を含める必要はありませ。ただし、署名に追加する場合は、それ必要です。 where T : DependencyObject

事実上、それらを公開しない限り、プロジェクトで必要なアセンブリ参照を使用できます。それらを公開すると、ライブラリを使用する他のすべてのプロジェクトがそれらを処理できる必要があるため、それらの参照自体が必要になります。

于 2012-09-27T02:53:28.447 に答える
0

ILMerge がこの問題を解決するかもしれません。アイデアは、2 つの dll を作成し、それらを 1 つにマージすることです。そうすれば、単一の dll を持つことができますが、それを 2 回参照できます。次に、GUIコードを他のコードから分離し、特定のプロジェクトに必要な参照のみを追加する方法.

于 2012-09-27T21:19:33.217 に答える
0

答えは簡単です。メソッドがパブリックとしてデカールされているためです。lib2.dllこれは、 (あなたの場合)に見えることを意味します。つまり、このメソッドを呼び出すことができます。

DependencyObjectまた、継承されたクラスのみがこのメソッドを呼び出すことができるという制約もあります。これが、'WindowsBase' を参照する必要がある理由です。

于 2012-09-28T09:10:57.290 に答える