Могу ли я сериализовать объект типа С#?
Я пытаюсь сериализовать объект 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
.
Ответы
Ответ 1
Я не знал, что объект Type может быть создан только с строкой, содержащей полное имя. Чтобы получить полное имя, вы можете использовать следующее:
string typeName = typeof (StringBuilder).FullName;
Затем вы можете сохранить эту строку, но она нужна, а затем восстановите тип следующим образом:
Type t = Type.GetType(typeName);
Если вам нужно создать экземпляр типа, вы можете сделать это:
object o = Activator.CreateInstance(t);
Если вы проверите значение o.GetType(), это будет StringBuilder, как и ожидалось.
Ответ 2
У меня была та же проблема, и моим решением было создать класс 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];
}
...
}
Вы также можете использовать AssemblyCualifiedName вместо Type.FullName - см. комментарий от @GreyCloud
Ответ 3
Ответ Брайана хорошо работает, если тип находится в той же самой сборке, что и вызов (например, GreyCloud указал в одном из комментариев).
Поэтому, если тип находится в другой сборке, вам нужно использовать 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;
}
Я отправляю это на тот случай, если кому-то это понадобится.
Ответ 4
В соответствии с документацией MSDN System.Type [1] вы можете сериализовать объект System.Type. Однако, поскольку ошибка явно ссылается на System.Text.StringBuilder, это, скорее всего, класс, вызывающий ошибку сериализации.
[1] Тип Класс (Система) - http://msdn.microsoft.com/en-us/library/system.type.aspx
Ответ 5
Просто посмотрел на его определение, он не помечен как 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)]