Я работаю над генератором метаданных, который в основном автоматически генерирует документацию для REST API.
Часть этого включает показ типов запросов / ответов, которые, конечно, могут быть DTO.Что мне нужно, так это сериализованная версия объекта в формате JSON (или XML), показывающая структуру и данные-заполнители.(Часть сериализации проста, это создание объекта, для начала это сложно).Так, например, учитывая объект:
public class MyObject {
public string Name { get; set; }
public int Age { get; set; }
public bool Active { get; set; }
}
Я хочу иметь возможность вызвать некоторую функцию:
var obj = GetDefaultValue(typeof(MyObject));
и получить эквивалент:
new MyObject { Name = string.Empty, Age = 0, Active = false };
// or in other words: new MyObject { Name = default(string), Age = default(int), Active = default(bool) };
У меня есть некоторый базовый код, который начинает делать это:
/// <summary>
/// Class to create a default value for a specified type.
/// </summary>
public abstract class DefaultValueGenerator
{
private DefaultValueGenerator() { }
/// <summary>
/// Creates a new default instance of type T.
/// Requires that T has a parameter-less constructor, or can be created using <code>default(T)</code>
/// </summary>
/// <param name="T"></param>
/// <returns></returns>
public static object GetDefaultValue(Type T)
{
try
{
return System.Activator.CreateInstance(T, true);
//TODO: if array type, also create a single item of that type
}
catch (Exception activatorException)
{
try
{
// from http://stackoverflow.com/a/2490267/7913
var defaultGeneratorType = typeof(DefaultGenerator<>).MakeGenericType(T);
return defaultGeneratorType.InvokeMember(
"GetDefault",
BindingFlags.Static |
BindingFlags.Public |
BindingFlags.InvokeMethod,
null, null, new object[0]);
}
catch //(Exception defaultGeneratorException)
{
throw new MissingMethodException(string.Format("No parameterless constructor defined for model {0}", T.Name), activatorException);
}
}
}
// from http://stackoverflow.com/a/2490267/7913
private class DefaultGenerator<T>
{
public static T GetDefault()
{
return default(T);
}
}
}
Итак, используя это, вы можете вызвать:
var obj = DefaultValueGenerator.GetDefaultValue(typeof(MyObject));
Одна из проблем этой реализации заключается в том, чтоесли вы звоните DefaultValueGenerator.GetDefaultValue(typeof(string))
, он выдает исключение, которое я ловлю как activatorException
, а затем использует ключевое слово default
.Просто безобразно, потому что я полагаюсь на исключение ... есть ли лучший способ?
Второй вопрос - массивы / коллекции.Например: DefaultValueGenerator.GetDefaultValue(typeof(List<MyObject>))
создает список из 0 элементов, который, в свою очередь, сериализуется в JSON как []
- не очень полезно с точки зрения документации.Я хотел бы, чтобы это генерировало один элемент.
Третья проблема - вложенные типы.Например, если у меня есть:
public class MyContainerObject {
public MyObject OtherObject { get; set; }
public int SomeValue { get; set; }
}
Я бы хотел, чтобы это сгенерировало эквивалент:
var obj = new MyContainerObject {
OtherObject = new MyObject { Name = string.Empty, Age = 0, Active = false },
SomeValue = 0,
}
, но фактически он генерирует OtherObject как нулевое значение.
Кто-нибудь знает какой-нибудь код / библиотеку, которая это уже делает?В противном случае, какие-либо советы о том, как сделать это, и избежать некоторых ошибок, которые я указал?Есть ли другой способ решить эту проблему, который был бы проще?
Я бы хотел, чтобы это работало для встроенных базовых типов (string, int, guid и т. Д.), А также для любых более сложных объектов -до тех пор, пока у них есть конструктор без параметров (я в порядке с этим ограничением, так как используемые типы должны быть POCO / DTO в любом случае).