Vra

Ek probeer om te serialize'n Tipe voorwerp in die volgende manier:

Type myType = typeof (StringBuilder);
var serializer = new XmlSerializer(typeof(Type));
TextWriter writer = new StringWriter();
serializer.Serialize(writer, myType);

Wanneer ek dit doen, die oproep om te Serialize gooi die volgende uitsondering:

"Die tipe Stelsel.Die teks.StringBuilder was nie verwag nie.Gebruik die XmlInclude of SoapInclude kenmerk te spesifiseer tipes wat nie bekend staties."

Is daar'n manier vir my om te serialize die Type voorwerp?Let wel dat ek nie probeer om te serialize die StringBuilder self, maar die Type voorwerp wat die metadata oor die StringBuilder die klas.

Was dit nuttig?

Oplossing

Ek was nie bewus daarvan dat 'n Tipe voorwerp kan geskep word met net 'n string met die ten volle gekwalifiseerde naam. Om die volle gekwalifiseerde naam kry, kan jy die volgende gebruik:

string typeName = typeof (StringBuilder).FullName;

Jy kan dan volhard hierdie string egter nodig, dan rekonstrueer die tipe soos volg:

Type t = Type.GetType(typeName);

As jy nodig het om 'n geval van die tipe skep, kan jy dit doen:

object o = Activator.CreateInstance(t);

As jy die waarde van o.GetType () kyk, sal dit wees StringBuilder, net soos jy sou verwag.

Ander wenke

Ek het dieselfde probleem, en my oplossing was om 'n SerializableType klas te skep. Dit vat vrylik na en van System.Type, maar dit serializes as 'n string. Al wat jy hoef te doen, is verklaar dat die veranderlike as 'n SerializableType, en van toe af kan jy verwys na dit as System.Type.

Hier is die klas:

// a version of System.Type that can be serialized
[DataContract]
public class SerializableType
{
    public Type type;

    // when serializing, store as a string
    [DataMember]
    string TypeString
    {
        get
        {
            if (type == null)
                return null;
            return type.FullName;
        }
        set
        {
            if (value == null)
                type = null;
            else
            {
                type = Type.GetType(value);
            }
        }
    }

    // constructors
    public SerializableType()
    {
        type = null;
    }
    public SerializableType(Type t)
    {
        type = t;
    }

    // allow SerializableType to implicitly be converted to and from System.Type
    static public implicit operator Type(SerializableType stype)
    {
        return stype.type;
    }
    static public implicit operator SerializableType(Type t)
    {
        return new SerializableType(t);
    }

    // overload the == and != operators
    public static bool operator ==(SerializableType a, SerializableType b)
    {
        // If both are null, or both are same instance, return true.
        if (System.Object.ReferenceEquals(a, b))
        {
            return true;
        }

        // If one is null, but not both, return false.
        if (((object)a == null) || ((object)b == null))
        {
            return false;
        }

        // Return true if the fields match:
        return a.type == b.type;
    }
    public static bool operator !=(SerializableType a, SerializableType b)
    {
        return !(a == b);
    }
    // we don't need to overload operators between SerializableType and System.Type because we already enabled them to implicitly convert

    public override int GetHashCode()
    {
        return type.GetHashCode();
    }

    // overload the .Equals method
    public override bool Equals(System.Object obj)
    {
        // If parameter is null return false.
        if (obj == null)
        {
            return false;
        }

        // If parameter cannot be cast to SerializableType return false.
        SerializableType p = obj as SerializableType;
        if ((System.Object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return (type == p.type);
    }
    public bool Equals(SerializableType p)
    {
        // If parameter is null return false:
        if ((object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return (type == p.type);
    }
}

en 'n voorbeeld van die gebruik:

[DataContract]
public class A
{

    ...

    [DataMember]
    private Dictionary<SerializableType, B> _bees;

    ...

    public B GetB(Type type)
    {
        return _bees[type];
    }

    ...

}

Jy kan dit ook oorweeg om die gebruik van AssemblyQualifiedName in plaas van Type.FullName - sien opmerking deur @GreyCloud

Brian se antwoord werk goed as die tipe is in dieselfde gemeente as die oproep (soos GreyCloud uitgewys in een van die kommentaar). So as die tipe is in 'n ander gemeente wat jy nodig het om die AssemblyQualifiedName as GreyCloud ook daarop gewys.

Maar as die AssemblyQualifiedName die weergawe spaar, indien u gemeentes het 'n ander weergawe as die een in die tou waar jy die tipe, dit sal nie werk nie.

In my geval was dit 'n kwessie en ek opgelos dit soos volg:

string typeName = typeof (MyClass).FullName;

Type type = GetTypeFrom(typeName);

object myInstance = Activator.CreateInstance(type);

GetTypeFrom Metode

private Type GetTypeFrom(string valueType)
    {
        var type = Type.GetType(valueType);
        if (type != null)
            return type;

        try
        {
            var assemblies = AppDomain.CurrentDomain.GetAssemblies();                

            //To speed things up, we check first in the already loaded assemblies.
            foreach (var assembly in assemblies)
            {
                type = assembly.GetType(valueType);
                if (type != null)
                    break;
            }
            if (type != null)
                return type;

            var loadedAssemblies = assemblies.ToList();

            foreach (var loadedAssembly in assemblies)
            {
                foreach (AssemblyName referencedAssemblyName in loadedAssembly.GetReferencedAssemblies())
                {
                    var found = loadedAssemblies.All(x => x.GetName() != referencedAssemblyName);

                    if (!found)
                    {
                        try
                        {
                            var referencedAssembly = Assembly.Load(referencedAssemblyName);
                            type = referencedAssembly.GetType(valueType);
                            if (type != null)
                                break;
                            loadedAssemblies.Add(referencedAssembly);
                        }
                        catch
                        {
                            //We will ignore this, because the Type might still be in one of the other Assemblies.
                        }
                    }
                }
            }                
        }
        catch(Exception exception)
        {
            //throw my custom exception    
        }

        if (type == null)
        {
            //throw my custom exception.
        }

        return type;
    }

Ek plaas hierdie in geval iemand nodig het.

Volgens die MSDN dokumentasie van System.Type [1] jy moet in staat wees om die System.Type voorwerp afleveringen. Maar as die fout is uitdruklik verwys na System.Text.StringBuilder, wat waarskynlik die klas wat die oorsaak is die serialisasie fout.

[1] Tik Klas (System) - http: // msdn.microsoft.com/en-us/library/system.type.aspx

Net kyk na die definisie, is dit nie gemerk as serialiseerbaar. As jy regtig hierdie data word afleveringen nodig het, dan kan jy dit om te skakel na 'n persoonlike klas wat gemerk is as sulks nie.

public abstract class Type : System.Reflection.MemberInfo
    Member of System

Summary:
Represents type declarations: class types, interface types, array types, value types, enumeration types, type parameters, generic type definitions, and open or closed constructed generic types.

Attributes:
[System.Runtime.InteropServices.ClassInterfaceAttribute(0),
System.Runtime.InteropServices.ComDefaultInterfaceAttribute(System.Runtime.InteropServices._Type),
System.Runtime.InteropServices.ComVisibleAttribute(true)]

Ek het gekom oor hierdie kwessie probeer om te doen binêre serialisasie in .netto standaard 2.0.Ek het uiteindelik tot die oplossing van die probleem met behulp van'n persoonlike SurrogateSelector en SerializationBinder.

Die TypeSerializationBinder was nodig omdat die raamwerk is met die oplossing van probleme System.RuntimeType voor dit het SurrogateSelector.Ek het nie regtig verstaan hoekom die tipe opgelos moet word voordat hierdie stap al...

Hier is die kodes:

// Serializes and deserializes System.Type
public class TypeSerializationSurrogate : ISerializationSurrogate {
    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) {
        info.AddValue(nameof(Type.FullName), (obj as Type).FullName);
    }

    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) {
        return Type.GetType(info.GetString(nameof(Type.FullName)));
    }
}

// Just a stub, doesn't need an implementation
public class TypeStub : Type { ... }

// Binds "System.RuntimeType" to our TypeStub
public class TypeSerializationBinder : SerializationBinder {
    public override Type BindToType(string assemblyName, string typeName) {
        if(typeName == "System.RuntimeType") {
            return typeof(TypeStub);
        }
        return Type.GetType($"{typeName}, {assemblyName}");
    }
}

// Selected out TypeSerializationSurrogate when [de]serializing Type
public class TypeSurrogateSelector : ISurrogateSelector {
    public virtual void ChainSelector(ISurrogateSelector selector) => throw new NotSupportedException();

    public virtual ISurrogateSelector GetNextSelector() => throw new NotSupportedException();

    public virtual ISerializationSurrogate GetSurrogate(Type type, StreamingContext context, out ISurrogateSelector selector) {
        if(typeof(Type).IsAssignableFrom(type)) {
            selector = this;
            return new TypeSerializationSurrogate();
        }
        selector = null;
        return null;
    }
}

Gebruik'n Voorbeeld:

byte[] bytes
var serializeFormatter = new BinaryFormatter() {
    SurrogateSelector = new TypeSurrogateSelector()
}
using (var stream = new MemoryStream()) {
    serializeFormatter.Serialize(stream, typeof(string));
    bytes = stream.ToArray();
}

var deserializeFormatter = new BinaryFormatter() {
    SurrogateSelector = new TypeSurrogateSelector(),
    Binder = new TypeDeserializationBinder()
}
using (var stream = new MemoryStream(bytes)) {
    type = (Type)deserializeFormatter .Deserialize(stream);
    Assert.Equal(typeof(string), type);
}
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top