Pot serializa un obiect C # Type?

Încerc să serializez un obiect Tip în felul următor:

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

Când fac acest lucru, apelul către Serialize aruncă următoarea excepție:

"Tipul System.Text.StringBuilder nu a fost așteptat   Atributul XmlInclude sau SoapInclude pentru a specifica tipurile care nu sunt   cunoscute în mod static. "

Există o modalitate de a serializa obiectul Type ? Rețineți că nu încerc să serializez codul StringBuilder , ci obiectul Type care conține metadatele despre clasa StringBuilder .

0
fr hi bn
De ce să prezinți tipul? Dacă desenizarea nu este. Nu se poate folosi, dacă este atunci tot ce trebuie să treci este numele complet calificat.
adăugat autor Keith, sursa
Acest cod exact ridică excepția în .net 6.1: A apărut o eroare la generarea documentului XML. System.RuntimeType este inaccesibil datorită nivelului său de protecție. Doar tipurile publice pot fi procesate.
adăugat autor YMC, sursa

5 răspunsuri

Nu știam că un obiect Type ar putea fi creat doar cu un șir care conține numele complet calificat. Pentru a obține numele complet calificat, puteți utiliza următoarele:

string typeName = typeof (StringBuilder).FullName;

Puteți persista apoi acest șir oricât de necesar, apoi reconstruiți tipul de genul acesta:

Type t = Type.GetType(typeName);

Dacă aveți nevoie să creați o instanță de tip, puteți face acest lucru:

object o = Activator.CreateInstance(t);

Dacă bifați valoarea o.GetType (), va fi StringBuilder, exact așa cum vă așteptați.

0
adăugat
Fiți avertizat că Type.GetType (typeName); va funcționa numai pentru tipuri în același ansamblu ca și apelul.
adăugat autor GreyCloud, sursa
soluția este de a utiliza AssemblyQualifiedName în loc de doar FullName
adăugat autor GreyCloud, sursa
Type.GetType() va eșua pentru tipurile generice.
adăugat autor Beriz, sursa

Conform documentației MSDN de tip System.Type [1], ar trebui să puteți serializa obiectul System.Type. Cu toate acestea, deoarece eroarea se referă în mod explicit la System.Text.StringBuilder, este probabil clasa care cauzează eroarea de serializare.

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

0
adăugat

Doar sa uitat la definiția sa, nu este marcată ca Serializabilă. Dacă aveți într-adevăr nevoie ca aceste date să fie serializate, atunci poate fi necesar să le convertiți într-o clasă personalizată care este marcată ca atare.

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)]
0
adăugat
Acum este decorat cu atributul Serializabil.
adăugat autor bjhuffine, sursa
Nu este adevărat, System.Type nu este serializabil, dar implementarea concretă System.RuntimeType este.
adăugat autor Felix K., sursa

Brian's answer works well if the type is in the same assembly as the call (like GreyCloud pointed out in one of the comments). So if the type is in another assembly you need to use the AssemblyQualifiedName as GreyCloud also pointed out.

Cu toate acestea, deoarece AssemblyQualifiedName salvează versiunea, dacă ansamblurile dvs. au o versiune diferită de cea din șirul în care aveți tipul, nu va funcționa.

În cazul meu a fost o problemă și am rezolvat-o astfel:

string typeName = typeof (MyClass).FullName;

Type type = GetTypeFrom(typeName);

object myInstance = Activator.CreateInstance(type);

Metoda GetTypeFrom

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

Am postat acest lucru în cazul în care cineva are nevoie de el.

0
adăugat

Am avut aceeași problemă, iar soluția mea era să creez o clasă SerializableType. Se convertește liber la și de la System.Type, dar este serializat ca un șir. Tot ce trebuie să faceți este să declarați variabila ca tip Serializable, și de atunci puteți să o referiți la ea ca System.Type.

Aici este clasa:

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

și un exemplu de utilizare:

[DataContract]
public class A
{

    ...

    [DataMember]
    private Dictionary _bees;

    ...

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

    ...

}

S-ar putea să considerați, de asemenea, folosirea AssemblyQualifiedName în loc de Type.FullName - a se vedea comentariul de la @GreyCloud

0
adăugat
+1 ar trebui să fie răspunsul conform cu formularea de întrebări a OP
adăugat autor Askolein, sursa
+1 De asemenea, s-ar putea să merită să înlocuiți toString() și să reveniți returnați acest tip.Type? .ToString (); ați folosi o clasă de tip tip.
adăugat autor Zachary Canann, sursa