两个Outlook VSTO插件间传递Object类型数据时出现类型转换异常的求助
解决Outlook插件跨项目传递自定义对象数组的COM代理转换错误
我之前也踩过跨Outlook COM加载项传递自定义对象的坑,你的错误Unable to cast object of type 'System.Runtime.Remoting.Proxies.__TransparentProxy'本质上是COM无法直接识别和传递你自定义的IProfileAttribute类型数组——当跨加载项调用方法时,.NET会把你的自定义对象包装成透明代理,而目标加载项无法将这个代理转换回你的原始自定义类型。
下面是几个经过验证的解决方案,按推荐程度排序:
方案1:序列化为字符串传递(最可靠,适配复杂类型)
把自定义对象序列化为JSON或XML字符串,以string类型传递(你已经确认string类型可以正常传递),目标加载项再反序列化回原始类型。
调用方代码修改:
public IProfileAttribute[] profileAttributes= null; Outlook.Application outlookApp = new Outlook.Application(); this.profileAttributes = new FilingNotifiableIpmlementation().FilingNotification(); // 填充对象 // 使用Newtonsoft.Json序列化(也可以用System.Text.Json) string attrJson = Newtonsoft.Json.JsonConvert.SerializeObject(this.profileAttributes); object destAddinName = "Tikit.CarpeDiem.AddIn.Outlook"; Office.COMAddIn destAddIn = outlookApp.COMAddIns.Item(ref destAddinName); destAddIn.Object.FilingNotification(attrJson);
目标加载项方法修改:
public void FilingNotification(string profileAttributesJson) { if (!string.IsNullOrEmpty(profileAttributesJson)) { // 反序列化回自定义数组 var profileAttributesList = Newtonsoft.Json.JsonConvert.DeserializeObject<IProfileAttribute[]>(profileAttributesJson); var x = profileAttributesList; } else { string y = "Try again"; } }
方案2:改用COM原生支持的集合类型传递
如果不想用序列化,可以把自定义数组转换为COM原生支持的ArrayList(而非自定义数组),因为COM能识别ArrayList类型。
调用方代码修改:
public IProfileAttribute[] profileAttributes= null; Outlook.Application outlookApp = new Outlook.Application(); this.profileAttributes = new FilingNotifiableIpmlementation().FilingNotification(); // 填充对象 // 转换为COM兼容的ArrayList System.Collections.ArrayList attrList = new System.Collections.ArrayList(this.profileAttributes); object destAddinName = "Tikit.CarpeDiem.AddIn.Outlook"; Office.COMAddIn destAddIn = outlookApp.COMAddIns.Item(ref destAddinName); destAddIn.Object.FilingNotification(attrList);
目标加载项方法修改:
public void FilingNotification(System.Collections.ArrayList profileAttributesList) { if (profileAttributesList != null) { // 转换回自定义类型数组 var profileAttributes = profileAttributesList.Cast<IProfileAttribute>().ToArray(); var x = profileAttributes; } else { string y = "Try again"; } }
关键注意事项(必看)
- 不管用哪种方案,你的
IProfileAttribute接口和实现类必须标记为COM可见,并且确保两个加载项引用的是同一个强命名且版本一致的程序集:[ComVisible(true)] [InterfaceType(ComInterfaceType.InterfaceIsDual)] // 确保COM能识别接口成员 public interface IProfileAttribute { // 你的属性定义 string AttributeName { get; set; } string AttributeValue { get; set; } } [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] // 避免自动生成类接口 public class ProfileAttribute : IProfileAttribute { public string AttributeName { get; set; } public string AttributeValue { get; set; } } - 部署时,要使用
regasm.exe注册包含自定义类型的程序集,带上/codebase参数(如果程序集不在GAC中):regasm.exe YourCustomAssembly.dll /codebase /tlb
内容的提问来源于stack exchange,提问作者Ashwani Tandon
相关产品推荐
相关产品推荐

