C# 很好地处理COM接口(MATLAB)缺少的引用

C# 很好地处理COM接口(MATLAB)缺少的引用,c#,matlab,C#,Matlab,我有一个参考MATLAB COM接口的VS2013 C#项目。应用程序90%的功能与MATLAB无关,我希望能够在MATLAB不可用的环境中编译和运行。期望的行为是: 构建,而不管引用是否存在(抛出警告) 如果MATLAB不可用,如果用户试图执行MATLAB特定的功能,请打印一条消息,但这不应该是致命的 我的第一个直觉是对不同的构建配置使用预处理器指令,但我希望避免这种情况,因为在设置连续集成和测试等时,它会变得混乱 所以我试着思考一下: try { var matlab = Activ

我有一个参考MATLAB COM接口的VS2013 C#项目。应用程序90%的功能与MATLAB无关,我希望能够在MATLAB不可用的环境中编译和运行。期望的行为是:

  • 构建,而不管引用是否存在(抛出警告)
  • 如果MATLAB不可用,如果用户试图执行MATLAB特定的功能,请打印一条消息,但这不应该是致命的
我的第一个直觉是对不同的构建配置使用预处理器指令,但我希望避免这种情况,因为在设置连续集成和测试等时,它会变得混乱

所以我试着思考一下:

try
{
  var matlab = Activator.CreateComInstanceFrom("appname.exe", "MLApp.MLApp").Unwrap();
}
catch
{
  //message
}
它抛出MissingMethodException(即,它找不到构造函数)。当存在MATLAB时,此功能正常工作:

     var matlab = new MLApp.MLApp();
最欢迎新想法,提前感谢

编辑: 请参阅下面的详细答案,但对于那些寻找快速测试代码的人,以下是对我有效的方法

        var Matlab_t = Type.GetTypeFromProgID("Matlab.Autoserver");

        if (Matlab_t != null)
            matlab = Activator.CreateInstance(Matlab_t);
        else
            MessageBox.Show("Matlab installation not found.\n");

在我的COM相关单元测试/检测器中,我只需分多个步骤进行:

  • 查找COM类型
  • 从类型创建COM对象
  • 调用方法
  • 释放COM对象,所有这些对象
  • 在您的情况下,我建议编写mapper类,将所有这些COM丑陋隐藏在抽象层之下。(我只是需要这些助手来测试我编写的COM库,所以正好相反)

    找不到类型时不抛出异常,而是简单地返回
    null

        public static object GetComObject(string typeName)
        {
            Type ComType;
    
            ComType = Type.GetTypeFromProgID(typeName);
            if (ComType == null)
            {
                //COM type not found
            }
            // Create an instance of your COM Registered Object.
            return Activator.CreateInstance(ComType);
        }
    
    创建(或不创建)对象时,我会使用
    dynamic
    或手写反射(做与dynamic相同的事情,但控制程度更高,在较旧的.NET版本中也能工作)

    工作完成后,你应该释放它们,所有的。在根COM对象中包括由方法返回(创建)的对象。(除了memleaks之外,释放父代而非其子代会导致单元测试引擎冻结,令人讨厌)


    谢谢还有很好的建议。现在,我也将丑陋封装在mapper类中。修复的关键是使用Type.GetTypeFromProgID和泛型CreateInstance方法,而不是CreateComInstanceFrom。@user102569只是不要忘记处理对象。我认为使用mapper with将非常适合这里(COM对象毕竟是本机资源)。
        public static object CallFunction(string method, string typeName, params object[] args)
        {
            Type ComType;
            object ComObject;
    
            ComType = Type.GetTypeFromProgID(typeName);
            if (ComType == null)
            {
                //COM type not found
            }
    
            // Create an instance of your COM Registered Object.
            ComObject = Activator.CreateInstance(ComType);
    
            // Call the Method and cast return to whatever it should be.
            return ComType.InvokeMember(method, BindingFlags.InvokeMethod, null, ComObject, args);
        }
    
        public static void DisposeCOM(dynamic obj)
        {
            if (obj != null)
            {
                Marshal.ReleaseComObject(obj);
            }
        }