我有动态加载的类(使用mef),它们是某种处理程序(这些工作正常)。
这些处理程序可以接收(有一个接收数据包并返回一个数据包的方法)数据包,它们都实现相同的接口(比如说IPacket)并返回一个答案(也就是一个IPacket)。
我收到这些数据包(通过tcp连接),我的程序不熟悉特定的类(虽然它是一个已知的接口--IPacket,但是一个不同的实现)。
因此,当我尝试反序列化数据包(将其交给处理程序)时,我得到一个异常。
我可以访问数据包实现的唯一方法应该是动态的,因为dll存储在我可以访问的文件夹中。
我认为我可以使用Assembly.LoadFrom来熟悉我的程序数据包,因为我甚至不需要实例化它们,只需反序列化(获取接口的实例)并移交给处理程序然后,它将返回一个答案,我会再次发送。
但它不起作用..
我假设我需要找到一种方法在运行时添加对这些dll的引用,然后我的程序将识别它们。(我认为可能在包类上使用Export(typeof()..)帮忙,不是吗?)
我在尝试反序列化时遇到的异常是找不到类名 ..
*我已经编辑了这个主题,我希望它有点清楚,谢谢=]
我并不是说这可以用mef来解决,我只是说它可以。 它绝对可以用反射来解决。我有一个文件夹,其中包含我希望程序在运行时识别的所有类,我只需要在运行时将其“加载”它们,就好像我在同一个文件夹中添加了对dll的引用。
基本上我需要做的是:
从文件夹加载某个接口的所有实现(本例中为IPacket)。我不需要实例化它们,而只需要将它们作为变量接收,而不会得到这样的类型不在我的项目中的异常。
所以我找到了这个片段:
static constructor() {
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
Assembly ayResult = null;
string sShortAssemblyName = args.Name.Split(',')[0];
Assembly[] ayAssemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly ayAssembly in ayAssemblies) {
if (sShortAssemblyName == ayAssembly.FullName.Split(',')[0]) {
ayResult = ayAssembly;
break;
}
}
return ayResult;
}
它似乎接近我正在寻找的但我实际上并不理解这一点。 有没有办法中断这个,以便它只加载某个文件夹中的dll? 那我的程序会不会熟悉dll?
此外,我们非常感谢对代码的解释。
答案 0 :(得分:1)
MEF肯定会帮助你,但不仅如此。您必须使用ISerializationSurrogate。下面的大多数解释都可以找到here。
因此,给定以下数据包接口定义:
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());
}
}
产生:
包信息:姓名:Joe
包信息:测量:42.42
答案 1 :(得分:0)
请查看this example,尤其是BindToType
方法。我想你可以检查装配是否已加载。如果不是,则使用反射(或MEF,如果您愿意)加载它。然后只需返回base.BindToType
即可。 (除非两台机器之间的装配版本不同,否则您可能需要自己找到该类型。)