2

我有一个应用程序,它在自身内部嵌入(通过 BuildAction:Embedded Resource)引用的程序集(称为 ClassLibrary1)并将其加载到 AppDomain.CurrentDomain.AssemblyResolve 事件中。主程序集定义了一个类 Class1:

public class Class1
{        
    public Class2 MyField { get; set; }    
}

它具有在 ClassLibrary1 中定义的 Class2 类型的属性。Class2的定义:

public class Class2
{
    public int A { get; set; }
}

在主要方法中,我正在创建一个新的 XmlSerializer(typeof(Class1)):

    static void Main()
    {
        SubscribeAssemblyResolver();
        MainMethod();
    }

    private static void MainMethod()
    {
        XmlSerializer xs2 = new XmlSerializer(typeof(Class1));
        Class1 cl = new Class1();
    }

执行程序时出现以下错误:

无法生成临时类(结果=1)。错误 CS0012:“ClassLibrary1.Class2”类型在未引用的程序集中定义。您必须添加对程序集“ClassLibrary1,Version=1.0.0.0,Culture=neutral,PublicKeyToken=c06f123f2868e8c8”的引用。错误 CS0266:无法将类型“object”隐式转换为“ClassLibrary1.Class2”。存在显式转换(您是否缺少演员表?)

有任何想法吗?

其余代码:

    private static void SubscribeAssemblyResolver()
    {
        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);            
    }

    static Dictionary<String, Assembly> _assemblies = new Dictionary<String, Assembly>(StringComparer.OrdinalIgnoreCase);

    static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        return ResolveAssembly(args.Name);
    }

    private static Assembly ResolveAssembly(string argsName)
    {
        Assembly dll;
        var name = "WindowsFormsApplication1.Libs." + new AssemblyName(argsName).Name + ".dll";
        if (!_assemblies.TryGetValue(name, out dll))
        {
            Assembly res = typeof(Program).Assembly;
            using (var input = res.GetManifestResourceStream(name))
            {
                if (input == null)
                {
                    //TODO: log
                    return null;
                }
                Byte[] assemblyData = new Byte[input.Length];
                input.Read(assemblyData, 0, assemblyData.Length);
                if (null == (dll = Assembly.Load(assemblyData)))
                {
                    //TODO: log
                    return null;
                }
                //TODO: log
                _assemblies[name] = dll;
                return dll;
            }
        }
        return dll;
    }

更新:在 microsoft Connect 站点上创建了一个BUG 。您还可以从那里下载一个示例 visual stuido 2010 解决方案(只需展开详细信息字段组)以重现它。

4

4 回答 4

0

尝试添加属性:

[XmlInclude(typeof(Class2))]
public class Class1
{        
   public Class2 MyField { get; set; }    
}
于 2011-05-19T09:17:41.363 回答
0

至于现在,我最终得到了两个有点糟糕的解决方案:

  1. 虽然您不能为 Class1 类型实例化 XmlSerializer,但您仍然可以从主程序集中为 Class2 类型实例化它。这确实意味着如果您将 Class1 移动到 ClassLibrary1 或将 Class2 移动到主程序集 - 它将反序列化而不会出现错误。它有效,但不可能在任何地方都使用这个解决方案,而且它在意识形态上是错误的。
  2. 使用ILMerge将这些程序集合并为一个。但它只适用于非 wpf 的东西,另外你应该使用程序集属性来管理情况(可能存在冲突)。

还有一个非常糟糕的主意:

  1. 使用 sgen.exe 生成 ClassLibrary1.XmlSerializer.dll。
  2. 也将其嵌入到主组件中。
  3. 通过反射将其显式加载到 XmlSerializer 缓存中,调用它的内部方法之一。

虽然我现在不得不使用第一个解决方案,但我对它并不满意,因为它太约束了。

于 2011-05-19T18:06:04.670 回答
0

我通过将程序集保存在临时文件夹中解决了类似的问题

    public static byte[] ReadFully(Stream input)
    {
        var buffer = new byte[16 * 1024];
        using (var ms = new MemoryStream())
        {
            int read;
            while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
            {
                ms.Write(buffer, 0, read);
            }
            return ms.ToArray();
        }
    }

    public App()
    {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        {
            var assemblyName = new AssemblyName(args.Name);

            if (assemblyName.Name != "Omikad.Core")
                return null;

            var resourceName = "Terem." + assemblyName.Name + ".dll";

            using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
            {
                if (stream == null)
                    return null;

                var assemblyData = ReadFully(stream);
                var tmp = Path.Combine(Path.GetTempPath(), "Omikad.Core.dll");
                File.WriteAllBytes(tmp, assemblyData);
                return Assembly.LoadFrom(tmp);
            }
        };
    }
于 2012-04-26T05:20:28.103 回答
0

我会尝试 XmlSerializer(Type, Type[]) 构造函数并使用第二个参数提供 Class2 作为附加类型。我对 XmlSerializer 的经验很少,但是对于 DataContractSerializer,这可以解决问题。

于 2014-01-23T15:37:25.640 回答