Question

Je suis en train de sérialiser un objet de Type de la manière suivante:

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

Quand je fais cela, l'appel à Sérialiser jette l'exception suivante:

"Le Système de type.Texte.StringBuilder n'était pas prévu.L'utilisation de la XmlInclude ou SoapInclude attribut pour spécifier les types qui ne sont pas connue statiquement."

Est-il un moyen pour moi de sérialiser l' Type l'objet?Notez que je n'essaie pas de sérialiser l' StringBuilder lui-même, mais l' Type objet contenant les métadonnées sur l' StringBuilder classe.

Était-ce utile?

La solution

Je n'étais pas au courant qu'un Type d'objet peut être créé avec seulement une chaîne de caractères contenant le nom pleinement qualifié.Pour obtenir le nom complet, vous pouvez utiliser les éléments suivants:

string typeName = typeof (StringBuilder).FullName;

Vous pouvez ensuite persister cette chaîne toutefois nécessaire, puis reconstruire le type comme ceci:

Type t = Type.GetType(typeName);

Si vous avez besoin de créer une instance du type, vous pouvez faire ceci:

object o = Activator.CreateInstance(t);

Si vous vérifiez la valeur de l'o.GetType(), il sera StringBuilder, juste comme vous le souhaitez.

Autres conseils

J'ai eu le même problème, et ma solution a été de créer un SerializableType classe.Librement convertit vers et à partir du Système.Type, mais il sérialise comme une chaîne de caractères.Tout ce que vous avez à faire est de déclarer la variable comme une SerializableType, et à partir de là, vous pouvez vous référer à elle comme Système.Type.

Ici, c'est la classe:

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

et un exemple d'utilisation:

[DataContract]
public class A
{

    ...

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

    ...

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

    ...

}

Vous pouvez également envisager d'utiliser AssemblyQualifiedName à la place du Type.FullName - voir le commentaire de @GreyCloud

De Brian réponse fonctionne bien que si le type est dans la même assemblée que l'appel (comme GreyCloud a souligné dans un des commentaires).Donc, si le type est dans une autre assemblée, vous devez utiliser la AssemblyQualifiedName comme GreyCloud également souligné.

Cependant, comme le AssemblyQualifiedName enregistre la version, si vos assemblées ont une version différente de celle de la chaîne où vous avez le type, il ne fonctionnera pas.

Dans mon cas, cela a été un problème et je l'ai résolu comme ceci:

string typeName = typeof (MyClass).FullName;

Type type = GetTypeFrom(typeName);

object myInstance = Activator.CreateInstance(type);

GetTypeFrom Méthode

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

Je vous poste ça au cas où quelqu'un en a besoin.

Selon la documentation MSDN de Système.Type [1] vous devez être en mesure de sérialiser le Système.Type d'objet.Cependant, comme l'erreur est en se référant explicitement au Système.Texte.StringBuilder, qui est probablement la classe qui est à l'origine de la sérialisation d'erreur.

[1] Type De Classe (Système) - http://msdn.microsoft.com/en-us/library/system.type.aspx

Juste regardé sa définition, il n'est pas marqué comme Sérialisable.Si vous avez vraiment besoin de ces données afin de sérialiser, alors vous pourriez avoir à les convertir à une classe personnalisée qui est marqué comme tel.

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

Je suis tombé sur ce problème en essayant de faire de la sérialisation binaire en .net standard 2.0.J'ai fini par résoudre le problème en utilisant un custom SurrogateSelector et SerializationBinder.

L' TypeSerializationBinder a été nécessaire parce que le cadre a de la difficulté à résoudre System.RuntimeType avant d'en arriver SurrogateSelector.Je ne comprends vraiment pas pourquoi le type doit être résolu avant cette étape si...

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

Exemple D'Utilisation:

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);
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top