如何一般地实例化COM类接口 [英] How can I instantiate a COM class interface generically

查看:360
本文介绍了如何一般地实例化COM类接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图重构一段代码,跑出了我可以想到的选项。



这是我原来的代码:

  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#中,您可以实例化 界面。)

  public static TInterface Get< TSubInterface,TInterface>()其中TSubInterface:TInterface 
{
< snip>剪辑>
if(!useComPartitions)
return Activator.CreateInstance< TSubInterface>(); // - >这不是合作

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

这里是我已经尝试过的:


  1. 我尝试指定new()约束,然后做一个'new TSubInterface()':
    这会导致构建错误:.. must一个非抽象类型与一个无参数的构造函数为了在通用类型或方法中使用它作为参数TSubInterface。


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


  3. ),我得到一个编译错误:无法转换表达式类型System.Runtime.Remoting.ObjectHandle返回类型TInterface


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



我可以以某种方式让这个编译和运行吗?

解决方案

你需要专注于能够创建一个类对象从接口名称。让我们选择一个人人都可以尝试的例子。创建一个新的控制台应用程序,并使用Project +添加引用,浏览标签并选择c:\windows\system32\shell32.dll。



使用对象浏览器生成的interop库。注意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
//代码大小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]属性。


I'm trying to refactor a piece of code and ran out of options I can think off.

This is the original code I had:

        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));  

And this is how I'm trying to refactor it:
(Yes, in C# you can 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(.....);
    }

Here's what I already tried:

  1. I tried specifying the new() constraint and then doing a 'new TSubInterface()': this results in a build error: "..must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TSubInterface' in the generic type or method.."

  2. when I use Activator.CreateInstance, I get a runtime exception: "Cannot create an instance of an interface"

  3. when I use Activator.CreateComInstanceFrom("someAssemblyName", "typeName"), I get a compilation error: "Cannot convert expression type 'System.Runtime.Remoting.ObjectHandle' to return type TInterface"

[edit] I was able to make this compile by adding 'where TSubInterface : class, but I'm not sure if that makes sense, since TSubInterface is an interface.
Using CreateComInstanceFrom also doesn't work, because it's trying to find the assembly which is specified in a directory where that dll is not and should not be.

Can I somehow make this compile and run?

解决方案

You'll need to focus on the seeming magic of being able to create a class object from an interface name. Let's pick an example that everybody can try. Create a new console application and use Project + Add Reference, Browse tab and select c:\windows\system32\shell32.dll.

Have a look at the interop library that generates with Object Browser. Note how the Shell type is an interface type. Now write this code:

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

Compile and run ildasm.exe on the .exe file. You'll see:

.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

Note how the type name got substituted from Shell to ShellClass. The type library importer created that class, it uses the original coclass name and append "Class" to the name. The compiler makes that substitution.

Which is the key, Activator.CreateInstance() is not able to make that same substitution. I don't see an obvious way to have generics make that same substitution, beyond directly using the IFooClass name instead of the interface name. Technically you can retrieve the [CoClass] attribute that the type library importer applied to the interface type.

这篇关于如何一般地实例化COM类接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆