Забудьте дженерики. Что если вы не знаете тип возвращаемого значения? Если вы используете Visual C # 2010 или более позднюю версию, это красота нового ключевого слова dynamic
. Ниже приведен пример класса сериализатора, который я написал, и пример использования, который принимает только строку XML и пытается проанализировать ее для общего типа System
, возвращая возвращаемое выходное значение в случае успеха. Вероятно, вы можете расширить его для других, более пользовательских типов, которые у вас есть, но им, вероятно, нужно иметь конструктор по умолчанию, и вам, вероятно, потребуется выполнить еще один разбор, чтобы получить имя типа и затем получить путь к нему в вашей сборке , Это немного сложно, но как только вы поймете, как работает приведенный ниже код, он начинает открывать кучу возможностей. Разве это не то, что вы ищете? Ваш вопрос спрашивает, как вернуть объект указанного типа, не зная этого типа (заметьте, однако, что вам все еще нужно иметь определение этого типа в своем коде, чтобы десериализовать его). Позволь мне объяснить. Если вы посмотрите, как assemblyFormatter
использовался в приведенном ниже коде, вы увидите, что его сложнее для типа, который вы определяете сами, например, struct
или enum
, потому что для этих типов вам придется передать assemblyFormatter
в качестве myObject.GetType().FullName
. Это строка, которую активатор использует для вызова конструктора по умолчанию вашего типа для его создания, чтобы иметь возможность создать из него сериализатор; это в основном сводится к сложности необходимости знать в вашей сборке это определение типа, чтобы иметь возможность десериализовать его.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using System.Xml.Serialization;
namespace DynamicSerializer
{
class Program
{
static void Main(string[] args)
{
bool myObject = true;
// There are a bunch of other examples you can try out:
// string myObject = "Hello, world.";
// long myObject = 1000;
// int myObject = 100;
string mySerializedObject;
if (Serializer.TrySerialize(myObject, out mySerializedObject))
{
Console.WriteLine("Serialized {0} as {1}.", myObject, mySerializedObject);
dynamic myDeserializedObject;
if (Serializer.TryDeserialize(mySerializedObject, out myDeserializedObject))
{
Console.WriteLine("Deserialized {0} as {1}.", mySerializedObject, myDeserializedObject);
}
}
Console.ReadLine();
}
class Serializer
{
public static bool TrySerialize(dynamic unserializedObject, out string serializedObject)
{
try
{
StringWriter writer = new StringWriter();
XmlSerializer serializer = new XmlSerializer(unserializedObject.GetType());
serializer.Serialize(writer, unserializedObject);
serializedObject = writer.ToString();
return true;
}
catch
{
serializedObject = null;
return false;
}
}
// The assemblyFormatter parameter is normally not passed in. However, it may be passed in for cases where the type is a special case (such as for enumerables or structs) that needs to be passed into the serializer. If this is the case, this value should be passed in as yourObject.GetType().FullName.
public static bool TryDeserialize(string serializedObject, out dynamic deserializedObjectOut, string assemblyFormatter = "System.{0}")
{
try
{
StringReader reader = new StringReader(serializedObject);
XDocument document = XDocument.Load(reader);
string typeString = null;
// Map the object type to the System's default value types.
switch (document.Root.Name.LocalName)
{
case "string":
typeString = "String";
break;
case "dateTime":
typeString = "DateTime";
break;
case "int":
typeString = "Int32";
break;
case "unsignedInt":
typeString = "UInt32";
break;
case "long":
typeString = "Int64";
break;
case "unsignedLong":
typeString = "UInt64";
break;
case "boolean":
typeString = "Boolean";
break;
case "double":
typeString = "Double";
break;
case "float":
typeString = "Single";
break;
case "decimal":
typeString = "Decimal";
break;
case "char":
typeString = "Char";
break;
case "short":
typeString = "Int16";
break;
case "unsignedShort":
typeString = "UInt16";
break;
case "byte":
typeString = "SByte";
break;
case "unsignedByte":
typeString = "Byte";
break;
}
if (assemblyFormatter != "System.{0}")
{
typeString = document.Root.Name.LocalName;
}
if (typeString == null)
{
// The dynamic object's type is not supported.
deserializedObjectOut = null;
return false;
}
if (typeString == "String")
{
// System.String does not specify a default constructor.
XmlSerializer serializer = new XmlSerializer(typeof(String));
reader = new StringReader(serializedObject);
deserializedObjectOut = serializer.Deserialize(reader);
}
else
{
object typeReference;
if (assemblyFormatter != "System.{0}")
{
typeReference = Activator.CreateInstance(Type.GetType(assemblyFormatter));
}
else
{
typeReference = Activator.CreateInstance(Type.GetType(String.Format(assemblyFormatter, typeString)));
}
XmlSerializer serializer = new XmlSerializer(typeReference.GetType());
reader = new StringReader(serializedObject);
deserializedObjectOut = serializer.Deserialize(reader);
}
return true;
}
catch
{
deserializedObjectOut = null;
return false;
}
}
}
}
}