我正在尝试以下列方式序列化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
类的元数据的对象.
我不知道只能使用包含完全限定名称的字符串创建Type对象.要获取完全限定名称,可以使用以下命令:
string typeName = typeof (StringBuilder).FullName;
然后,您可以根据需要保留此字符串,然后重建类型如下:
Type t = Type.GetType(typeName);
如果需要创建该类型的实例,可以执行以下操作:
object o = Activator.CreateInstance(t);
如果你检查o.GetType()的值,它将是StringBuilder,就像你期望的那样.
我有同样的问题,我的解决方案是创建一个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_bees; ... public B GetB(Type type) { return _bees[type]; } ... }
您也可以考虑使用AssemblyQualifiedName而不是Type.FullName - 请参阅@GreyCloud的评论
如果类型与调用在同一个程序集中(如其中一条注释中指出的GreyCloud),Brian的答案很有效.因此,如果类型在另一个程序集中,则需要使用AssemblyQualifiedName,因为GreyCloud也指出了这一点.
但是,由于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; }
我发布这个以防任何人需要它.