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 サイトにバグを作成しました。サンプルの Visual stuido 2010 ソリューション (詳細フィールドグループを展開するだけ) をダウンロードして再現することもできます。

4

4 に答える 4

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[]) コンストラクターを試し、2 番目のパラメーターを使用して Class2 を追加の型として提供します。XmlSerializer の経験はほとんどありませんが、DataContractSerializer の場合はこれでうまくいきます。

于 2014-01-23T15:37:25.640 に答える
0

今のところ、私は2つのやや悪い解決策に行き着きました:

  1. Class1 型に対して XmlSerializer をインスタンス化することはできませんが、メイン アセンブリから Class2 型に対してインスタンス化することはできます。つまり、Class1 を ClassLibrary1 に、または Class2 をメイン アセンブリに移動すると、エラーなしで逆シリアル化されます。機能しますが、このソリューションをどこでも使用することはできません。また、イデオロギー的にも間違っています。
  2. ILMergeを使用して、これらのアセンブリを 1 つにマージします。ただし、それは wpf 以外のものに対してのみ機能し、さらにアセンブリ属性を使用して状況を管理する必要があります (競合が発生する可能性があります)。

そして、非常に悪い考えが 1 つあります。

  1. sgen.exe で ClassLibrary1.XmlSerializer.dll を生成します。
  2. 本体にも組み込みます。
  3. リフレクションを介して内部メソッドの 1 つを呼び出す XmlSerializer キャッシュに明示的にロードします。

今のところ解決策 1 を使用する必要がありましたが、制約が多すぎて満足できません。

于 2011-05-19T18:06:04.670 に答える