我正在尝试重构一段代码并且用尽了我能想到的选项。
这是我原来的代码:
if (WebConfigSettings.ComPartition == null && HttpContext.Current != null)
Nses = new NSession();
else
Nses = (INSession)Marshal.BindToMoniker(string.Format("partition:{0}/new:NuntioServer.NSession", WebConfigSettings.ComPartition));
AND
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#中你可以instantiate an interface。)
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(.....);
}
这是我已经尝试过的:
我尝试指定new()约束,然后执行'new TSubInterface()': 这会导致构建错误:“..必须是具有公共无参数构造函数的非抽象类型,以便在泛型类型或方法中将其用作参数'TSubInterface'。”
当我使用Activator.CreateInstance时,我收到运行时异常:“无法创建接口实例”
当我使用Activator.CreateComInstanceFrom(“someAssemblyName”,“typeName”)时,我得到一个编译错误:“无法将表达式类型'System.Runtime.Remoting.ObjectHandle'转换为返回类型TInterface”
[edit] 我能够通过添加'where TSubInterface:class来进行编译,但我不确定这是否有意义,因为TSubInterface是一个接口。
使用CreateComInstanceFrom也不起作用,因为它试图找到在dll不存在且不应存在的目录中指定的程序集。
我可以以某种方式编译并运行吗?
答案 0 :(得分: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]属性。
答案 1 :(得分:0)
可以通过弄清楚该接口的coClass是什么来创建一个实例:
var coClassAttribute = type.GetCustomAttribute<CoClassAttribute>(); // our extension method
return (TSubInterface)Activator.CreateInstance(coClassAttribute.CoClass);
我对此并不满意,但它确实有效。 (不会将此标记为正确答案)