Создавать экземпляр типа, включающего все свойства объекта и придерживаться наследования
Я не уверен, что этот заголовок отражает реальный вопрос, поэтому позвольте мне объяснить. Есть ли способ создать экземпляр класса и рекурсивно создать все свойства, являющиеся классами?
Например:
public class Base
{
public int BaseValue{ get; set;}
}
public class Extended : Base
{
public int ExtendedValue{ get; set;}
public AnotherExtendedClass AnotherClass { get; set;}
}
Я хотел бы создать полезную нагрузку json, состоящую из пустого экземпляра Extended
с всеми значениями и значениями, заданными по умолчанию. И используйте его как:
string representation = Test.CreateDefaultEmptyJson(Extended);
public static string CreateDefaultEmptyJson(Type type)
{
JsonSerializerSettings settings = new JsonSerializerSettings().Configure();
var defaultInstance= Activator.CreateInstance(type);
return JsonConvert.SerializeObject(defaultInstance, settings);
}
Выход не включает свойства Extended
класса. Я вернусь:
{
"BaseValue":0
}
Когда я действительно хотел бы увидеть (или что-то подобное):
{
"BaseValue":0,
{
"ExtendedValue":0,
{
...
}
}
}
Я предполагаю, что я мог бы рекурсивно перебирать все типы Extended
и вызывать конструктор по умолчанию, однако, прежде чем я спускаюсь по этой дороге, может быть несколько строк кода, чтобы сделать то же самое.
Насколько я знаю, нет встроенного способа сделать это, не написав собственный рекурсивный метод.
Однако, предполагая, что:
то вы можете создать такой метод примерно в дюжине строк кода:
public static string CreateDefaultEmptyJson(Type type)
{
return JsonConvert.SerializeObject(RecursiveCreateInstance(type), Formatting.Indented);
}
public static object RecursiveCreateInstance(Type type)
{
object obj = null;
ConstructorInfo ctor = type.GetConstructor(Type.EmptyTypes);
if (ctor != null)
{
obj = ctor.Invoke(null);
foreach (PropertyInfo prop in type.GetProperties())
{
Type propType = prop.PropertyType;
if (prop.CanWrite && propType.IsClass)
{
prop.SetValue(obj, RecursiveCreateInstance(propType));
}
}
}
return obj;
}
Скрипт: https://dotnetfiddle.net/3VMTsC
Если вышеприведенные предположения не выполняются, то вещи быстро усложняются. Если вы сталкиваетесь с проблемами, когда вам нужен простой способ создания поддельных объектов для целей тестирования, тогда вам может понадобиться изучить фальшивую структуру.
Этот поспешно написанный класс начинает решать ваш вопрос. Он возвращает устанавливаемые свойства, возвращающие ссылочные типы и проходящие через них рекурсивно, создавая экземпляры по мере необходимости.
Он не охватывает
- Индексированные свойства Глубина рекурсии
Возможно, вам лучше настроить параметры по умолчанию для самих свойств, чтобы класс не создавался с нежелательными нулями.
public class PropertyPopulator
{
public void PopulateProperties(object target)
{
var properties = target.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.PropertyType.IsClass && p.CanWrite && p.CanRead);
foreach (var property in properties)
{
var propertyValue = property.GetValue(target);
if (propertyValue == null)
{
var constructor = property.PropertyType.GetConstructor(new Type[] { });
if (constructor != null)
{
propertyValue = constructor.Invoke(new object[] { });
property.SetValue(target, propertyValue);
PopulateProperties(propertyValue);
}
}
}
}
}