Frage

Ich bin versucht zu serialisieren Sie ein Objekt Geben, in der folgenden Weise:

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

Wenn ich dies tun, wird der Anruf zu Serialisieren, wirft die folgende Ausnahme:

"Das Typ-System.Text.StringBuilder war nicht zu erwarten.Verwenden Sie die XmlInclude-oder SoapInclude-Attribut, um anzugeben, dass Typen, die nicht bekannt ist statisch."

Gibt es eine Möglichkeit für mich zu serialisieren Type Objekt?Beachten Sie, dass ich bin nicht versucht, Sie zu serialisieren StringBuilder selbst, sondern die Type Objekt mit den Metadaten über die StringBuilder Klasse.

War es hilfreich?

Lösung

Ich war nicht bewusst, dass ein Typ-Objekt erzeugt werden konnte, nur mit einem string, der vollständig qualifizierte name.Um den vollständig qualifizierten Namen verwenden, können Sie das folgende:

string typeName = typeof (StringBuilder).FullName;

Sie können dann bestehen diese Zeichenfolge jedoch erforderlich, rekonstruieren Sie dann die Art wie dieser:

Type t = Type.GetType(typeName);

Wenn Sie brauchen, um erstellen Sie eine Instanz des Typs, können Sie dies tun:

object o = Activator.CreateInstance(t);

Wenn Sie überprüfen Sie den Wert von a.GetType(), es wird StringBuilder, so wie man es erwarten würde.

Andere Tipps

Ich hatte das gleiche problem und meine Lösung war die Schaffung einer SerializableType Klasse.Es frei konvertiert in und aus dem System.Geben, aber es serialisiert wird, wie ein string.Alles, was Sie tun müssen, ist, deklarieren Sie die variable als SerializableType, und dann ab auf den Sie sich beziehen können, um es als System.Typ.

Hier ist die Klasse:

// 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);
    }
}

und ein Beispiel der Nutzung:

[DataContract]
public class A
{

    ...

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

    ...

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

    ...

}

Sie sollten auch mit AssemblyQualifiedName anstelle von Art.FullName - siehe Kommentar von @GreyCloud

Brian s Antwort funktioniert gut, wenn der Typ in derselben assembly wie der Ruf (wie GreyCloud wies darauf hin, in einem der Kommentare).Also wenn der Typ in einer anderen assembly, die Sie verwenden müssen AssemblyQualifiedName als GreyCloud auch hingewiesen.

Doch als der AssemblyQualifiedName speichert die version, wenn Sie Ihre Versammlungen haben eine andere version als die in der Zeichenfolge, wobei Sie den Typ, es wird nicht funktionieren.

In meinem Fall war dies ein Problem, und ich löste es wie folgt:

string typeName = typeof (MyClass).FullName;

Type type = GetTypeFrom(typeName);

object myInstance = Activator.CreateInstance(type);

GetTypeFrom Methode

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;
    }

Ich bin dieses posting, in Fall, dass jemand es braucht.

Laut der MSDN-Dokumentation von System.Typ [1] Sie sollten in der Lage sein zu serialisieren Sie das System.Typ Objekt.Jedoch, als der Fehler wird ausdrücklich unter Bezugnahme auf System.Text.StringBuilder, dass wahrscheinlich die Klasse, wodurch die Serialisierung Fehler.

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

Nur sah seine definition, es ist nicht als Serialisierbar markiert.Wenn Sie wirklich müssen diese Daten zu serialisieren, dann müssen Sie konvertieren Sie es in eine benutzerdefinierte Klasse, die als solche gekennzeichnet.

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)]

Ich stieß auf dieses Problem versuchen zu tun binäre Serialisierung in .net standard 2.0.Ich landete lösen das problem mit einem custom SurrogateSelector und SerializationBinder.

Die TypeSerializationBinder war erforderlich, da der Rahmen war Probleme lösen System.RuntimeType bevor es bekam SurrogateSelector.Ich weiß wirklich nicht verstehen, warum die Art die behoben werden müssen, vor diesem Schritt, obwohl...

Hier ist der code:

// 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;
    }
}

Beispiel:

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);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top