Создавать экземпляр типа, включающего все свойства объекта и придерживаться наследования

93
4

Я не уверен, что этот заголовок отражает реальный вопрос, поэтому позвольте мне объяснить. Есть ли способ создать экземпляр класса и рекурсивно создать все свойства, являющиеся классами?

Например:

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 и вызывать конструктор по умолчанию, однако, прежде чем я спускаюсь по этой дороге, может быть несколько строк кода, чтобы сделать то же самое.

спросил(а) 2021-01-13T23:55:07+03:00 1 неделя назад
1
Решение
59

Насколько я знаю, нет встроенного способа сделать это, не написав собственный рекурсивный метод.
Однако, предполагая, что:

ваши классы имеют конструкторы без параметров (по умолчанию) непримитивные свойства - это все конкретные типы (не интерфейсы) и у вас нет каких-либо опорных циклов в вашей структуре классов,

то вы можете создать такой метод примерно в дюжине строк кода:

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

Если вышеприведенные предположения не выполняются, то вещи быстро усложняются. Если вы сталкиваетесь с проблемами, когда вам нужен простой способ создания поддельных объектов для целей тестирования, тогда вам может понадобиться изучить фальшивую структуру.

ответил(а) 2021-01-13T23:55:07+03:00 1 неделя назад
60

Этот поспешно написанный класс начинает решать ваш вопрос. Он возвращает устанавливаемые свойства, возвращающие ссылочные типы и проходящие через них рекурсивно, создавая экземпляры по мере необходимости.

Он не охватывает

    Индексированные свойства Глубина рекурсии

Возможно, вам лучше настроить параметры по умолчанию для самих свойств, чтобы класс не создавался с нежелательными нулями.

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);
}
}
}
}
}

ответил(а) 2021-01-13T23:55:07+03:00 1 неделя назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема