0

コードの一部をリファクタリングしようとしていますが、考えられるオプションが不足しています。

これは私が持っていた元のコードです:

        if (WebConfigSettings.ComPartition == null && HttpContext.Current != null)
            Nses = new NSession();
        else
            Nses = (INSession)Marshal.BindToMoniker(string.Format("partition:{0}/new:NuntioServer.NSession", WebConfigSettings.ComPartition));

        if (WebConfigSettings.ComPartition == null && HttpContext.Current != null)
            apses.Wses = new WSession();
        else
            apses.Wses = (IWSession)Marshal.BindToMoniker(string.Format("partition:{0}/new:NuntioServer.WSession", WebConfigSettings.ComPartition));  

そして、これは私がそれをリファクタリングしようとしている方法です:
(はい、C# ではインターフェイスインスタンス化 できます。)

    public static TInterface Get<TSubInterface, TInterface>() where TSubInterface: TInterface
    {
        <snip></snip>
        if (!useComPartitions)
            return Activator.CreateInstance<TSubInterface>(); // --> this is not cooperating

        return (TInterface)Marshal.BindToMoniker(.....);
    }

これが私がすでに試したことです:

  1. new() 制約を指定してから 'new TSubInterface()' を実行しようとしました: これによりビルド エラーが発生します。 ' ジェネリック型またはメソッドで.."

  2. Activator.CreateInstance を使用すると、「インターフェイスのインスタンスを作成できません」という実行時例外が発生します。

  3. Activator.CreateComInstanceFrom("someAssemblyName", "typeName") を使用すると、次のコンパイル エラーが発生します。

[編集] 'where TSubInterface : class を追加することでこれをコンパイルできましたが、TSubInterface はインターフェイスであるため、それが意味があるかどうかはわかりません。
CreateComInstanceFrom の使用も機能しません。これは、その dll が存在しないディレクトリで指定されているアセンブリを検索しようとしているためです。

どうにかしてこれをコンパイルして実行できますか?

4

2 に答える 2

2

インターフェイス名からクラス オブジェクトを作成できるという魔法のように見えることに注目する必要があります。誰もが試すことができる例を選びましょう。新しいコンソール アプリケーションを作成し、[プロジェクト] + [参照の追加] の [参照] タブを使用して、c:\windows\system32\shell32.dll を選択します。

Object Browser で生成される相互運用ライブラリを見てください。Shell タイプがインターフェイス タイプであることに注意してください。次のコードを記述します。

class Program {
    static void Main(string[] args) {
        var shl = new Shell32.Shell();
    }
}

.exe ファイルで ildasm.exe をコンパイルして実行します。わかるでしょ:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       8 (0x8)
  .maxstack  1
  .locals init ([0] class [Interop.Shell32]Shell32.Shell 'shl')
  IL_0000:  nop
  IL_0001:  newobj     instance void [Interop.Shell32]Shell32.ShellClass::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ret
} // end of method Program::Main

型名がShell から ShellClassにどのように置き換えられたかに注意してください。タイプ ライブラリ インポーターがそのクラスを作成し、元のコクラス名を使用して、名前に "Class" を追加します。コンパイラはその置換を行います。

Activator.CreateInstance() は同じ置換を行うことができません。インターフェイス名の代わりに IFooClass 名を直接使用する以外に、ジェネリックに同じ置換を行わせる明確な方法がわかりません。技術的には、タイプ ライブラリ インポーターがインターフェイス型に適用した [CoClass] 属性を取得できます。

于 2012-09-28T12:41:43.507 に答える
0

これは、そのインターフェイスの coClass を特定し、そのインスタンスを作成することで実行できます

var coClassAttribute = type.GetCustomAttribute<CoClassAttribute>(); // our extension method
return (TSubInterface)Activator.CreateInstance(coClassAttribute.CoClass);

私はこれに満足していませんが、うまくいきます。(これを正解としてマークしません)

于 2012-09-28T12:37:27.323 に答える