2008-08-15 99 views
40

我试图序列通过以下方式Type对象:我可以序列化一个C#类型对象吗?

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

当我这样做,将序列的调用抛出了以下异常:

“之类System.Text。 StringBuilder不是预期的,使用 XmlInclude或SoapInclude属性来指定非静态已知的类型 。“

有没有办法让我序列化Type对象?请注意,我并非试图序列化StringBuilder本身,而是包含有关StringBuilder类的元数据的Type对象。

+1

为什么要序列化类型?如果反序列化不是.Net,它就不能使用它,如果它是那么你需要传递的是完全限定名。 – Keith 2008-08-15 14:48:08

+0

此确切代码在.net 6.1中引发了异常:生成XML文档时发生错误。 System.RuntimeType由于其保护级别而不可访问。只有公共类型可以被处理。 – YMC 2017-01-11 02:00:08

回答

73

我不知道,一个类型对象可以与仅含有完全限定名称的字符串被创建。要获得完全合格的名称,可以使用以下命令:

string typeName = typeof (StringBuilder).FullName; 

然后,您可以坚持这个字符串但需要,然后重建这样的类型:

Type t = Type.GetType(typeName); 

如果你需要创建一个实例类型的,你可以这样做:

object o = Activator.CreateInstance(t); 

如果检查o.GetType()的值,这将是StringBuilder的,就像你期望的那样。

1

刚刚看过它的定义,它没有标记为可序列化。如果您确实需要将这些数据序列化,那么您可能必须将其转换为标记为这样的自定义类。

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

不是,`System.Type`不是可序列化的,但具体实现`System.RuntimeType`是。 – 2012-05-29 08:46:26

+0

现在它用Serializable属性装饰了。 – bjhuffine 2015-08-25 14:12:26

10

我有同样的问题,我的解决方案是创建一个SerializableType类。它可以自由地转换为System.Type或从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]; 
    } 

    ... 

} 

您还可以考虑使用AssemblyQualifiedName代替Type.FullName - 见注释通过@GreyCloud

5

Brian's如果类型与调用在同一个程序集中(如GreyCloud在其中一个注释中指出的那样),answer可以很好地工作。 因此,如果类型在另一个程序集中,则需要使用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; 
    } 

我张贴这种的情况下,任何人都需要它。

相关问题