Отражение не может конвертировать объект - PullRequest
0 голосов
/ 15 декабря 2018

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

Вы можете мне помочь?

public class Destinatary 
{
    public string DetinataryID { get; set; }
    public string Name { get; set; }
    public Address Address { get; set; }


}

public class Address
{
    public string Place { get; set; }
    public string PostalCode { get; set; }
}


class Program
{
    static void Main(string[] args)
    {
        Destinatary destinataryTest = new Destinatary();
        Type type = typeof(Destinatary);
        destinataryTest = GenerateDataSample(destinataryTest);

        Console.WriteLine($"Name: {destinataryTest.Name}");
        Console.WriteLine($"Place: {destinataryTest.Address.PostalCode}");
        Console.WriteLine($"City: {destinataryTest.Address.City.Name}");
        Console.ReadLine();
    }

    private static T GenerateDataSample<T>(T classToWork)
    {
        Type typeToWork = typeof(T);
        object tipoInstance = Activator.CreateInstance(typeToWork);
        foreach (var classProperty in typeToWork.GetProperties())
        {

            if (classProperty.PropertyType.FullName.StartsWith("System."))
            {
                var propertyVal = RandomString(10,false ); 
                classProperty.SetValue(tipoInstance, propertyVal, null);
            }
            else
            {
                var instanceIntermediate = Activator.CreateInstance(classProperty.PropertyType);
                instanceIntermediate = GenerateDataSample(instanceIntermediate);                    
                classProperty.SetValue(tipoInstance, instanceIntermediate, null); //here there is a probleman (Cant convert Object to Address)

            }
        }

        return (T)tipoInstance;
    }

}

Ответы [ 3 ]

0 голосов
/ 15 декабря 2018

var instanceIntermediate = Activator.CreateInstance(... - в этой строке тип времени компиляции instanceIntermediate равен object.Поэтому, когда вы вызываете GenerateDataSample(instanceIntermediate), он вызывает GenerateDataSample<object>(instanceIntermediate), а не GenerateDataSample<Address>(instanceIntermediate), как вы, вероятно, ожидаете.

Исправлено: поскольку GenerateDataSample на самом деле не заботится о входном параметре, а только вводит его - измените его с универсальногообычному методу взятия типа - object GenerateDataSample(Type typeToWork)

0 голосов
/ 15 декабря 2018

Почему вы хотите конвертировать значение?Объект уже имеет тип Address, а метод set объявлен как

public void SetValue (object obj, object value);

, т. Е. Он принимает переменную типа object.

Проблема возникает при вызове GenerateDataSample<T>(), поскольку T определяется во время компиляции, а тип времени компиляции instanceIntermediate равен object, поэтому GenerateDataSample всегда будет пытаться создать объект типа System.Object для свойств.Не делайте GenerateDataSample универсальным.

Кроме того, вам на самом деле не нужно передавать экземпляр, а только тип GenerateDataSample.

private static object GenerateDataSample(Type typeToWork)
{
    object tipoInstance = Activator.CreateInstance(typeToWork);
    foreach (PropertyInfo classProperty in typeToWork.GetProperties()) {
        object propertyVal;
        if (classProperty.PropertyType == typeof(string)) {
            propertyVal = RandomString(10, false);
        } else {
            propertyVal = GenerateDataSample(classProperty.PropertyType);
        }
        classProperty.SetValue(tipoInstance, propertyVal);
    }
    return tipoInstance;
}

Вы также можете создатьперегруженная универсальная версия:

private static T GenerateDataSample<T>()
{
    return (T)GenerateDataSample(typeof(T));
}

Затем вы можете создать пример данных с помощью:

Destinatary destinataryTest = GenerateDataSample<Destinatary>();
0 голосов
/ 15 декабря 2018

Обобщения разрешаются во время компиляции, а не во время выполнения.

В этой строке

instanceIntermediate = GenerateDataSample(instanceIntermediate); 

instanceIntermediate является объектом Address, но здесь компилятор знает только, что это объект,Поэтому он вызывает GenerateDataSample, который создаст объект в этой строке

object tipoInstance = Activator.CreateInstance(typeToWork);

Чтобы GenerateDataSample создал экземпляр типа объекта classToWork, используйте

object tipoInstance = Activator.CreateInstance(classToWork.GetType());
...