60

次の方法で Type オブジェクトをシリアル化しようとしています。

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

これを行うと、Serialize の呼び出しで次の例外がスローされます。

「型 System.Text.StringBuilder は予期されていませんでした。XmlInclude または SoapInclude 属性を使用して、静的に認識されていない型を指定してください。」

Typeオブジェクトをシリアル化する方法はありますか? StringBuilderそれ自体をシリアル化しようとしているのではなく、クラスTypeに関するメタデータを含むオブジェクトをシリアル化しようとしていることに注意してください。StringBuilder

4

6 に答える 6

98

完全修飾名を含む文字列のみで Type オブジェクトを作成できることを知りませんでした。完全修飾名を取得するには、次を使用できます。

string typeName = typeof (StringBuilder).FullName;

その後、必要に応じてこの文字列を永続化し、次のように型を再構築できます。

Type t = Type.GetType(typeName);

タイプのインスタンスを作成する必要がある場合は、次のようにすることができます。

object o = Activator.CreateInstance(t);

o.GetType() の値を確認すると、予想どおり StringBuilder になります。

于 2008-08-15T15:12:43.373 に答える
14

私は同じ問題を抱えていました。私の解決策は、SerializableType クラスを作成することでした。System.Type との間で自由に変換しますが、文字列としてシリアル化します。変数を SerializableType として宣言するだけで、それ以降は System.Type として参照できます。

クラスは次のとおりです。

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

および使用例:

[DataContract]
public class A
{

    ...

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

    ...

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

    ...

}

Type.FullName の代わりに AssemblyQualifiedName の使用を検討することもできます - @GreyCloud のコメントを参照してください

于 2012-03-21T17:34:43.790 に答える
10

タイプが呼び出しと同じアセンブリにある場合、ブライアンの答えはうまく機能します(GreyCloudがコメントの1つで指摘したように)。したがって、型が別のアセンブリにある場合は、GreyCloud も指摘したようにAssemblyQualifiedNameを使用する必要があります。

ただし、AssemblyQualifiedNameはバージョンを保存するため、アセンブリのバージョンが文字列内の型のバージョンと異なる場合、機能しません。

私の場合、これは問題であり、次のように解決しました。

string typeName = typeof (MyClass).FullName;

Type type = GetTypeFrom(typeName);

object myInstance = Activator.CreateInstance(type);

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

誰かがそれを必要とする場合に備えて、これを投稿しています。

于 2014-01-29T15:19:01.660 に答える
2

System.Type [1] の MSDN ドキュメントによると、System.Type オブジェクトをシリアル化できるはずです。ただし、エラーは System.Text.StringBuilder を明示的に参照しているため、シリアル化エラーの原因となっているクラスである可能性があります。

[1] 型クラス (システム) - http://msdn.microsoft.com/en-us/library/system.type.aspx

于 2008-08-15T14:50:59.097 に答える
1

その定義を見ただけで、Serializable としてマークされていません。このデータをシリアル化する必要がある場合は、そのようにマークされたカスタム クラスに変換する必要がある場合があります。

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)]
于 2008-08-15T14:50:09.520 に答える