C# 加载未知类型

C# 加载未知类型,c#,reflection,mef,C#,Reflection,Mef,我有动态加载的类(使用mef),它们是某种处理程序(这些处理程序工作得很好) 这些处理程序可以接收(有一个方法接收一个数据包并返回一个)数据包,所有这些数据包都实现了相同的接口(比如IPacket)并返回一个答案(同样是IPacket) 我接收到这些数据包(通过tcp连接),而我的程序并不熟悉特定的类(尽管它是一个已知的接口—IPacket,但却是一个不同的实现) 因此,当我尝试反序列化一个数据包(将其交给处理程序)时,我得到一个异常 我将一个反序列化返回到一个对象(使用二进制序列化程序)中的

我有动态加载的类(使用mef),它们是某种处理程序(这些处理程序工作得很好)

这些处理程序可以接收(有一个方法接收一个数据包并返回一个)数据包,所有这些数据包都实现了相同的接口(比如IPacket)并返回一个答案(同样是IPacket)

我接收到这些数据包(通过tcp连接),而我的程序并不熟悉特定的类(尽管它是一个已知的接口—IPacket,但却是一个不同的实现)

因此,当我尝试反序列化一个数据包(将其交给处理程序)时,我得到一个异常

  • 我将一个反序列化返回到一个对象(使用二进制序列化程序)中的数据序列化为字节*
我访问数据包实现的唯一方法应该是动态的,因为DLL存储在我可以访问的文件夹中

我想我可以使用Assembly.LoadFrom来熟悉程序中的数据包,因为我甚至不需要重新设置它们,只需反序列化(获取接口实例)并将其交给处理程序,处理程序将返回一个答案,然后我会再次发送

但是它不起作用

我假设我需要找到一种方法在运行时添加对这些DLL的引用,然后我的程序将识别它们。。(我认为在pack类上使用Export(typeof()…)可能会有所帮助,是吗?)

尝试反序列化时遇到的异常是找不到类名

*我已经编辑了这个主题,希望它更清晰一点,谢谢你=]


  • 编辑:
我并不是说这是可以用mef解决的,我只是认为这是可以的。 这肯定是可以通过反思来解决的。我有一个文件夹,其中包含我希望我的程序在运行时识别的所有类,我只需要让它在运行时“加载”它们,就像我在同一个文件夹中添加了对DLL的引用一样

所以基本上我需要做的是:

从文件夹加载特定接口(本例中为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());
    }
}