11

BinaryFormatterアセンブリのさまざまなバージョン間で作業を行おうとしています。逆シリアル化する実際のクラスは、各アセンブリ バージョンでまったく同じですが、逆シリアル化では、オブジェクトがシリアル化されているため、元のアセンブリ名が含まれているBinaryFormatterため、適切なアセンブリが見つからないと不平を言っています。そこで、常に現在のアセンブリ バージョンに逆シリアル化するように SerializationBinder指示するカスタムを作成しました。BinaryFormatter

私のスキームは機能し、オブジェクトを正しく逆シリアル化できますが、オブジェクトが T のリストである場合は機能しません。ここで、T はアセンブリの古いバージョンからシリアル化された型です。

型パラメーターがアセンブリのクラスであるリストやその他のジェネリック型でこれを機能させる方法はありますか?

//the object i want to deserialize
class MyObject
{
     public string Name{get;set;}
}

//my binder class
class MyBinder : SerializationBinder
{
    static string assemblyToUse = typeof (MyObject).Assembly.FullName;
    public override Type BindToType(string assemblyName, string typeName)
    {
        var isMyAssembly = assemblyName.StartsWith("oldAssemblyName");
        var assemblyNameToUse = isMyAssembly ? assemblyToUse : assemblyName;
        var tn = typeName + ", " + assemblyNameToUse;
        return Type.GetType(tn);            
    }
}


//my deserialize method
static object BinaryDeserialize(string input)
{
    var arr = Convert.FromBase64String(input);
    var ms = new MemoryStream(arr);
    ms.Seek(0, SeekOrigin.Begin);
    var bf = new BinaryFormatter();
    bf.Binder = new MyBinder();
    var obj = bf.Deserialize(ms);

    return obj;
}

static void Test()
{
    //this works
    //serialized(new MyObject());
    var str = ReadSerialized_MyObject();  
    var obj = BinaryDeserialize(str);

    //this doesn't work
    //serialized(new List<MyObject>());
    var str2 = ReadSerialized_List_of_MyObject(); 
    var obj = BinaryDeserialize(str2);
}
4

4 に答える 4

7

バージョン1.0.0.0アセンブリからList<MyClass>のインスタンスをシリアル化した場合、SerializationBinder.BindToType関数は次のタイプを提供するように求められます。

System.Collections.Generic.List`1[[MyAssembly.MyClass, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=12345678901234567890]]

List <MyClass>タイプをバージョン2.0.0.0アセンブリに再マップするには、タイプ名を次のように変更する必要があります。

System.Collections.Generic.List`1[[MyAssembly.MyClass, MyAssembly]]

注意すべき主な点は、アセンブリ名が完全に修飾されていないことです。アセンブリ名を2.0.0.0バージョン番号で完全に修飾しようとすると、機能しません。

于 2011-11-04T20:16:38.390 に答える
1

アプリケーション A は、List(Result) を含む Serialized Binary フォーマッタ ファイル「SerializedList.bin」を作成します。ここで、Result は Serializable オブジェクトです。ここで、アプリケーション B はファイルを DeSerialize して List(Result) オブジェクトにロードしたいと考えています。これが私がそれを機能させた方法です..

参照: http://social.msdn.microsoft.com/forums/en-US/netfxremoting/thread/eec2b7a6-65f8-42d1-ad4f-409f46bdad61

アプリケーション A のアセンブリ名は「Serialize」
アプリケーション B のアセンブリ名は「DeSerialize」

アプリケーション A コード (シリアル化):

namespace Serialize
{
class Program
{
    static void Main(string[] args)
    {            
        List<Result> result = ;//Get From DB

        IFormatter formatter = new BinaryFormatter();
        Stream sStream = new FileStream(
            "SerializedList.bin",
            FileMode.CreateNew,
            FileAccess.Write,
            FileShare.None);

        formatter.Serialize(sStream, result);
        sStream.Close();           
    }
}

}

いくつかの結果オブジェクト:

[Serializable]
public class Result
{
    public decimal CONTACT_ID { get; set; }
    public decimal INSTITUTION_NBR { get; set; }
}

アプリケーション B コード (デシリアライズ):

namespace DeSerialize
{
class Program
{
    static void Main(string[] args)
    {
        IFormatter formatter = new BinaryFormatter();

        string fromTypeName = "System.Collections.Generic.List`1[[Serialize.Result, Serialize, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]";
        string fromTypeName1 = "Serialize.Result";

        string toTypename = "System.Collections.Generic.List`1[DeSerialize.Result]";
        string toTypename1 = "DeSerialize.Result";
        string toTypeAssemblyName = Assembly.GetExecutingAssembly().FullName;

        DictionarySerializationBinder dic = new DictionarySerializationBinder();
        dic.AddBinding(fromTypeName, toTypename);
        dic.AddAssemblyQualifiedTypeBinding(fromTypeName1, toTypename1, toTypeAssemblyName);

        formatter.Binder = dic;

        Stream dStream = new FileStream(
            "SerializeList.bin",
            FileMode.Open,
            FileAccess.Read,
            FileShare.Read);

        List<Result> listDS =
            (List<Result>)formatter.Deserialize(dStream);

        dStream.Close();
    }
}

sealed class DictionarySerializationBinder : SerializationBinder
{
    Dictionary<string, Type> _typeDictionary = new Dictionary<string, Type>();

    public override Type BindToType(string assemblyName, string typeName)
    {
        Type typeToReturn;

        if (_typeDictionary.TryGetValue(typeName, out typeToReturn))
        {
            return typeToReturn;
        }

        else
        {
            return null;
        }
    }

    public void AddBinding(string fromTypeName, string toTypeName)
    {

        Type toType = Type.GetType(toTypeName);

        if (toType == null)
        {
            throw new ArgumentException(string.Format(
            "Help, I could not convert '{0}' to a valid type.", toTypeName));
        }

        _typeDictionary.Add(fromTypeName, toType);

    }

    public void AddAssemblyQualifiedTypeBinding(string fromTypeName, string toTypeName, string toTypeAssemblyName)
    {

        Type typeToSerializeTo = GetAssemblyQualifiedType(toTypeAssemblyName, toTypeName);

        if (typeToSerializeTo == null)
        {

            throw new ArgumentException(string.Format(

            "Help, I could not convert '{0}' to a valid type.", toTypeName));

        }

        _typeDictionary.Add(fromTypeName, typeToSerializeTo);

    }

    private static Type GetAssemblyQualifiedType(string assemblyName, string typeName)
    {

        return Type.GetType(String.Format("{0}, {1}", typeName, assemblyName));

    }
}    

}

于 2013-05-20T20:06:12.863 に答える
0

メソッドを呼び出すときに、イベントを処理AppDomain.AssemblyResolveして目的のアセンブリを返すだけです。Type.GetTypeそれはそれと同じくらい簡単です!

于 2018-11-29T10:51:08.067 に答える