反射不能转换对象

时间:2018-12-15 19:58:48

标签: c# reflection casting type-conversion

我想使用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 :(得分:1)

泛型在编译时而不是在运行时解析。

在这一行

instanceIntermediate = GenerateDataSample(instanceIntermediate); 

instanceIntermediate是一个Address对象,但此处的编译器仅知道它是一个对象。因此它调用了GenerateDataSample,它将在此行中构造一个对象

object tipoInstance = Activator.CreateInstance(typeToWork);

要让GenerateDataSample创建对象classToWork类型的实例,请使用

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

答案 1 :(得分:1)

为什么要转换值?该对象已经是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>();

答案 2 :(得分:0)

var instanceIntermediate = Activator.CreateInstance(...-在这一行,instanceIntermediate的编译时间类型为object。因此,当您致电GenerateDataSample(instanceIntermediate)时,它是在致电GenerateDataSample<object>(instanceIntermediate)而不是您可能期望的GenerateDataSample<Address>(instanceIntermediate)

修复:由于GenerateDataSample实际上并不关心输入参数,而只是键入-将其从通用方法更改为常规方法,并采用类型-object GenerateDataSample(Type typeToWork)