1

最近、古いバージョンのDLLとの互換性を確保するために、コードを変更する必要がありました。DLLは同じ名前であり、署名されていません。違いは、新しいDLLに追加されたいくつかの追加メソッドにもあります。

私には正しくないように思われるこれを回避する1つの方法は、プロジェクト内の新しいDLLを参照し、ビルドして実行することです。他のDLLを使用する場合は、binフォルダーでそれを置き換えるだけです。Reflectionを使用してコンストラクター内のメソッドの存在を確認するだけでエラーを回避し、フラグを設定して、古いバージョンを使用している場合に後で新しい関数を呼び出さないようにすることができます。

私にとって奇妙なことは、古いバージョンを使用すると、次のコードが機能しないことです。

int[] someVariable = (DLLIsNewFormat) ? DLL.CallNewMethod() : new int[5];

基本的に何が起こっているのかというと、DLLIsNewFormatはFalseですが、何らかの理由でエラーが発生します。

メソッドが見つかりません:'Int32 [][NameSpace]。[Class].CallNewMethod()'。

これを実行する最善の方法は、おそらく各関数が存在するかどうかを確認してから、リフレクションを使用してそれらを呼び出すことであることを理解しています。しかし、なぜコードがこのように動作しているのかわかりません。これは未定義の動作ですか?

4

2 に答える 2

0

必要なのは、存在しないメソッドへの呼び出しをJITから隠すことです。

そのためには、関数内で行われた存在しない各呼び出しとそのような関数の呼び出しがバージョン条件によって制御されていることを確認する必要があります。

private int[] WrappedNewMethod()
{
  return DLL.CallNewMethod();
}

...SomeOtherMethod()
{
   int[] someVariable = (DLLIsNewFormat) ? WrappedNewMethod(): new int[5];
}
于 2013-03-22T21:28:53.460 に答える
0

これは、スニペットを含むメソッドがJITコンパイルされたときに発生します。JITコンパイルを実行するには、メソッドが呼び出されたときにメソッドが使用可能である必要があります。メソッドが使用できないため、このコードを含むメソッドが呼び出されると、メソッドが実行される前に、JITコンパイラーがこの例外をスローします。

これを回避する1つの方法は、新しいメソッドを定義することです。

int[] HideCall()
{
    return DLL.CallNewMethod();
}

次に、直接ではなくこのメソッドを呼び出しますDLL.CallNewMethod()

より良い解決策は、「条件付きDLL」と、このDLLを条件付きで使用しているアセンブリの両方によって参照されるアセンブリでインターフェイスを定義することです。このインターフェイスのデフォルトの実装をメインアセンブリで使用できるようにし、代替の実装を条件付きで使用されるDLLで使用できるようにします。

次に、実行時に、DLLが使用可能かどうかを確認し、リフレクションを使用してこのインターフェイスを実装するクラスのインスタンスを構築し、デフォルトの実装への参照をこれに置き換えます。

コード例:

// Interface, in an assembly visible to both of the other assemblies.
public interface IDLLInterface
{
    int[] CallNewMethod();
}

// Implementation in the main program.
class DefaultDLLImplementation : IDLLInterface
{
    public int[] CallNewMethod()
    {
        return new int[5];
    }
}

static class DLLImplementation
{
    public readonly IDLLInterface Instance;

    static DLLImplementation()
    {
        // Pseudo-code
        if (DllIsAvailable) {
            Instance = ConstructInstanceFromDllUsingReflection();
        } else {
            Instance = new DefaultDLLImplementation();
        }
    }
}

その後、代わりに使用できDLLImplementation.Instance.CallNewMethod()、適切なメソッドが自動的に呼び出されます。

もちろん、インターフェイスにわかりやすい名前を付けて、その意味が明確になるようにすることをお勧めします。

于 2013-03-22T21:30:10.083 に答える