C# 加载未知类型
我有动态加载的类(使用mef),它们是某种处理程序(这些处理程序工作得很好) 这些处理程序可以接收(有一个方法接收一个数据包并返回一个)数据包,所有这些数据包都实现了相同的接口(比如IPacket)并返回一个答案(同样是IPacket) 我接收到这些数据包(通过tcp连接),而我的程序并不熟悉特定的类(尽管它是一个已知的接口—IPacket,但却是一个不同的实现) 因此,当我尝试反序列化一个数据包(将其交给处理程序)时,我得到一个异常C# 加载未知类型,c#,reflection,mef,C#,Reflection,Mef,我有动态加载的类(使用mef),它们是某种处理程序(这些处理程序工作得很好) 这些处理程序可以接收(有一个方法接收一个数据包并返回一个)数据包,所有这些数据包都实现了相同的接口(比如IPacket)并返回一个答案(同样是IPacket) 我接收到这些数据包(通过tcp连接),而我的程序并不熟悉特定的类(尽管它是一个已知的接口—IPacket,但却是一个不同的实现) 因此,当我尝试反序列化一个数据包(将其交给处理程序)时,我得到一个异常 我将一个反序列化返回到一个对象(使用二进制序列化程序)中的
- 我将一个反序列化返回到一个对象(使用二进制序列化程序)中的数据序列化为字节*
- 编辑:
所以我找到了这个片段:
static constructor() {
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
这似乎是接近我所寻找的,但我并不真正理解这一点。
有没有一种方法可以对其进行MIDI,使其仅加载某个文件夹中的DLL?
我的程序会熟悉DLL吗
另外,如果您能解释一下代码,我们将不胜感激。请特别查看
BindToType
方法。我想你可以检查一下组件是否已加载。如果不是,则使用反射(或MEF,如果您愿意)加载它。然后只需返回base.BindToType
,它就可以工作了。(除非两台机器的装配版本不同,否则您可能需要自己找到类型。)MEF肯定会帮助您,但不仅仅是它。你必须使用。下面的大部分解释你都可以找到
因此,给定以下数据包接口定义:
public interface IPacket
{
string GetInfo();
}
您有以下实现,它们驻留在自己的程序集中:
[Export(typeof(IPacket))]
class FirstPacket : IPacket
{
public FirstPacket()
{
Name = "Joe";
}
public string Name { get; set; }
public string GetInfo()
{
return "Name: " + Name;
}
}
[Export(typeof(IPacket))]
class SecondPacket : IPacket
{
public SecondPacket()
{
Measurement = 42.42m;
}
public decimal Measurement { get; set; }
public string GetInfo()
{
return "Measurement: " + Measurement;
}
}
现在我们将定义另一个接口,类似于:
public interface IPacketSurrogateProvider
{
void AddSurrogate(SurrogateSelector toSelector);
}
以及在定义具体数据包的同一程序集中的匹配实现:
[Export(typeof(IPacketSurrogateProvider))]
class FirstPacketSurrogateProvider : IPacketSurrogateProvider, ISerializationSurrogate
{
public void AddSurrogate(SurrogateSelector toSelector)
{
toSelector.AddSurrogate(typeof(FirstPacket), new StreamingContext(StreamingContextStates.All), this);
}
public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
{
info.AddValue("Name", ((FirstPacket)obj).Name);
}
public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
{
((FirstPacket)obj).Name = info.GetString("Name");
return obj;
}
}
[Export(typeof(IPacketSurrogateProvider))]
class SecondPacketSurrogateProvider : IPacketSurrogateProvider, ISerializationSurrogate
{
public void AddSurrogate(SurrogateSelector toSelector)
{
toSelector.AddSurrogate(typeof(SecondPacket), new StreamingContext(StreamingContextStates.All), this);
}
public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
{
info.AddValue("Measurement", ((SecondPacket)obj).Measurement);
}
public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
{
((SecondPacket)obj).Measurement = info.GetDecimal("Measurement");
return obj;
}
}
现在,在一个程序集中,它确实引用了具有接口的程序集,但没有引用具有实现的程序集,并且具有与上述两个程序集相同的部署文件夹:
public static void Test()
{
var container = new CompositionContainer(new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)));
var packets = container.GetExportedValues<IPacket>().ToArray();
var packetSurrogateProviders = container.GetExportedValues<IPacketSurrogateProvider>();
var surrogateSelector = new SurrogateSelector();
foreach (var provider in packetSurrogateProviders)
{
provider.AddSurrogate(surrogateSelector);
}
var deserializedPackets = new IPacket[] { };
using (var stream = new MemoryStream())
{
var formatter = new BinaryFormatter {SurrogateSelector = surrogateSelector};
formatter.Serialize(stream, packets);
stream.Position = 0;
deserializedPackets = (IPacket[])formatter.Deserialize(stream);
}
foreach (var packet in deserializedPackets)
{
Console.WriteLine("Packet info: {0}", packet.GetInfo());
}
}
公共静态无效测试()
{
var container=new CompositionContainer(new DirectoryCatalog(Path.GetDirectoryName(Assembly.getexecutinggassembly().Location));
var packets=container.GetExportedValues().ToArray();
var packetsubrogateproviders=container.GetExportedValues();
var progatetselector=新的progatetselector();
foreach(packetsubrogateproviders中的var提供程序)
{
提供者。添加代理(代理选择者);
}
var deserializedPackets=新IPacket[]{};
使用(var stream=new MemoryStream())
{
var formatter=new BinaryFormatter{subscrateselector=subscrateselector};
序列化(流、数据包);
流位置=0;
反序列化数据包=(IPacket[])格式化程序。反序列化(流);
}
foreach(反序列化数据包中的var数据包)
{
WriteLine(“包信息:{0}”,Packet.GetInfo());
}
}
产生:
包信息:姓名:乔
数据包信息:测量值:42.42
您正在使用什么反序列化程序?你有什么例外?我已经编辑了你的标题。请看“,”其中的共识是“不,他们不应该”。你能再解释一下吗?您正在导出类型,但MEF没有加载该类型或正在发生什么?只是想了解这里发生了什么:您正在将计算机1上的类型A序列化为数据包,而在计算机2上,您希望反序列化包含未知类型A的数据包。您希望在此处使用MEF实现什么?场景似乎很清楚。在计算机B上运行的应用程序想要反序列化它从未听说过的类型a。那该怎么办?也许一些示例代码将有助于理解您是如何使用MEF来解决这个问题的。谢谢您的回答,但我有一些问题。谢谢您的回答,但我有一些问题。为什么我需要代理类?我可以使用mef将所有IPacket加载到一个IPacket列表中,而不使用它,我很确定我的程序会识别它们。。我只是想,因为我实际上不需要它们出现在列表中,所以我会让我的程序在运行时以某种方式识别它们。。在我看来,它应该更简单,我有路径并且可以加载程序集,它不需要太多的工作..您必须理解,在我的示例中,通过MEF导出/加载数据包只是为了方便。
public static void Test()
{
var container = new CompositionContainer(new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)));
var packets = container.GetExportedValues<IPacket>().ToArray();
var packetSurrogateProviders = container.GetExportedValues<IPacketSurrogateProvider>();
var surrogateSelector = new SurrogateSelector();
foreach (var provider in packetSurrogateProviders)
{
provider.AddSurrogate(surrogateSelector);
}
var deserializedPackets = new IPacket[] { };
using (var stream = new MemoryStream())
{
var formatter = new BinaryFormatter {SurrogateSelector = surrogateSelector};
formatter.Serialize(stream, packets);
stream.Position = 0;
deserializedPackets = (IPacket[])formatter.Deserialize(stream);
}
foreach (var packet in deserializedPackets)
{
Console.WriteLine("Packet info: {0}", packet.GetInfo());
}
}