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()”:这会导致构建错误:“..必​​须是具有公共无参数构造函数的非抽象类型才能将其用作参数 'TSubInterface ' 在泛型类型或方法中.."

  2. 当我使用 Activator.CreateInstance 时,我得到一个运行时异常:“无法创建接口的实例”

  3. 当我使用 Activator.CreateComInstanceFrom("someAssemblyName", "typeName") 时,出现编译错误:“无法将表达式类型 'System.Runtime.Remoting.ObjectHandle' 转换为返回类型 TInterface”

[编辑]我可以通过添加 'where TSubInterface : 类来进行编译,但我不确定这是否有意义,因为 TSubInterface 是一个接口。
使用 CreateComInstanceFrom 也不起作用,因为它试图找到在该 dll 不存在且不应该存在的目录中指定的程序集。

我可以以某种方式编译并运行它吗?

4

2 回答 2

2

您需要专注于能够从接口名称创建类对象的表面魔力。让我们选择一个每个人都可以尝试的例子。创建一个新的控制台应用程序并使用 Project + Add Reference,Browse 选项卡并选择 c:\windows\system32\shell32.dll。

查看使用对象浏览器生成的互操作库。请注意 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 的。类型库导入器创建了该类,它使用原始的 coclass 名称并将“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 回答