Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 通过反射设置属性时的类型转换问题_C#_Reflection - Fatal编程技术网

C# 通过反射设置属性时的类型转换问题

C# 通过反射设置属性时的类型转换问题,c#,reflection,C#,Reflection,我们有一个long?类型的属性,它用int填充 当我直接设置属性obj.Value=v时,这很好enum开始,让 //枚举对象负责此转换 如果(valueToSet!=null) { valueToSet=Enum.ToObject(targetType,valueToSet); } } 其他的 { //返回具有指定System.Type且其值为的System.Object //等效于指定的对象。 valueToSet=Convert.ChangeType(valueToSet,targetTy

我们有一个
long?
类型的属性,它用
int
填充

当我直接设置属性
obj.Value=v时,这很好info.SetValue(obj,v,null)它为我提供了以下例外情况:

“System.Int32”类型的对象无法转换为“System.Nullable`1[System.Int64]”类型

这是一个简化的场景:

    class TestClass
    {
        public long? Value { get; set; }
    }

    [TestMethod]
    public void TestMethod2()
    {
        TestClass obj = new TestClass();
        Type t = obj.GetType();

        PropertyInfo info = t.GetProperty("Value");
        int v = 1;

        // This works
        obj.Value = v;

        // This does not work
        info.SetValue(obj, v, null);
    }
为什么通过反射设置属性时它不起作用,而直接设置属性时它起作用?

查看全文:

如果您正在为可为null的类型设置值,则为完整代码

public static void SetValue(object inputObject, string propertyName, object propertyVal)
{
    //find out the type
    Type type = inputObject.GetType();

    //get the property information based on the type
    System.Reflection.PropertyInfo propertyInfo = type.GetProperty(propertyName);

    //find the property type
    Type propertyType = propertyInfo.PropertyType;

    //Convert.ChangeType does not handle conversion to nullable types
    //if the property type is nullable, we need to get the underlying type of the property
    var targetType = IsNullableType(propertyType) ? Nullable.GetUnderlyingType(propertyType) : propertyType;

    //Returns an System.Object with the specified System.Type and whose value is
    //equivalent to the specified object.
    propertyVal = Convert.ChangeType(propertyVal, targetType);

    //Set the value of the property
    propertyInfo.SetValue(inputObject, propertyVal, null);

}
private static bool IsNullableType(Type type)
{
    return type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>));
}
您需要这样做,因为您无法将任何任意值转换为给定类型…因此您需要在编写以下内容时将其转换为如下所示:

obj.Value = v;
编译器知道如何为您执行正确的强制转换,并实际编译

obj.Value = new long?((long) v);

使用反射时,没有编译器可以帮助您。

因为类型
long
具有隐式转换方法

您可以将隐式转换方法视为存在于
=
符号后面的隐藏方法

它也适用于可为空的类型:

int i = 0;
int? j = i; // Implicit conversion
long k = i; // Implicit conversion
long? l = i; // Implicit conversion
但是反过来是不行的,因为不存在将
null
传递给非null的隐式转换:

int? i = 0;
int j = i; // Compile assert. An explicit conversion exit... 
int k = (int)i; // Compile, but if i is null, you will assert at runtime.
您不必显式地将
int
转换为
int?
。。。或者一个
长?

但是,当您使用反射时,您将绕过隐式转换并直接将值指定给属性。这样,您必须显式地转换它

info.SetValue(obj, (long?)v, null);

反思跳过所有隐藏在
=

后面的甜言蜜语巩固和扩展的答案,以按照建议(和回答)处理
枚举,并将累积的知识放在一个地方。这更容易复制/复制

private void SetApiSettingValue(object source, string propertyName, object valueToSet)
{
    // find out the type
    Type type = source.GetType();

    // get the property information based on the type
    System.Reflection.PropertyInfo property = type.GetProperty(propertyName);

    // Convert.ChangeType does not handle conversion to nullable types
    // if the property type is nullable, we need to get the underlying type of the property
    Type propertyType = property.PropertyType;
    var targetType = IsNullableType(propertyType) ? Nullable.GetUnderlyingType(propertyType) : propertyType;

    // special case for enums
    if (targetType.IsEnum)
    {
        // we could be going from an int -> enum so specifically let
        // the Enum object take care of this conversion
        if (valueToSet != null)
        {
            valueToSet = Enum.ToObject(targetType, valueToSet);
        }
    }
    else
    {
        // returns an System.Object with the specified System.Type and whose value is
        // equivalent to the specified object.
        valueToSet = Convert.ChangeType(valueToSet, targetType);
    }

    // set the value of the property
    property.SetValue(source, valueToSet, null);
}

private bool IsNullableType(Type type)
{
    return type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>));
}
private void SetApiSettingValue(对象源、字符串属性名称、对象值设置)
{
//找出类型
Type Type=source.GetType();
//根据类型获取属性信息
System.Reflection.PropertyInfo property=type.GetProperty(propertyName);
//Convert.ChangeType不处理到可为空类型的转换
//如果属性类型可为null,则需要获取属性的基础类型
类型propertyType=property.propertyType;
var targetType=IsNullableType(propertyType)?Nullable.GetUnderlyingType(propertyType):propertyType;
//枚举的特殊情况
if(targetType.IsEnum)
{
//我们可以从int->enum开始,让
//枚举对象负责此转换
如果(valueToSet!=null)
{
valueToSet=Enum.ToObject(targetType,valueToSet);
}
}
其他的
{
//返回具有指定System.Type且其值为的System.Object
//等效于指定的对象。
valueToSet=Convert.ChangeType(valueToSet,targetType);
}
//设置属性的值
SetValue(source,valueToSet,null);
}
私有bool IsNullableType(类型)
{
返回type.IsGenericType&&type.GetGenericTypeDefinition().Equals(typeof(Nullable));
}

在以反射方式创建新对象时,我也遇到了这个问题

这是如何避免的:

  var newOne = Activator.CreateInstance(srcProp.GetType());

  srcProp.SetValue(newGameData, newOne, null);
  var newOne = Activator.CreateInstance(srcProp.PropertyType);

  srcProp.SetValue(newGameData, newOne, null);
这就是如何做到这一点:

  var newOne = Activator.CreateInstance(srcProp.GetType());

  srcProp.SetValue(newGameData, newOne, null);
  var newOne = Activator.CreateInstance(srcProp.PropertyType);

  srcProp.SetValue(newGameData, newOne, null);

这是旧线。但此页面中的解决方案不起作用。我做了一些调整,效果很好(在.netcore2.0中)

obj=Activator.CreateInstance();
foreach(obj.GetType().GetProperties()中的PropertyInfo属性)
{
如果(!object.Equals(this.reader[prop.Name],DBNull.Value))
{
if(prop.PropertyType.Name.Contains(“Nullable”))
{
prop.SetValue(obj,Convert.ChangeType(this.reader[prop.Name],null.getUnderlineType(prop.PropertyType)),null);
}
其他的
{
prop.SetValue(obj,this.reader[prop.Name],null);
}
}
}

var properties=propTypes.GetProperty(属性)

TypeCode TypeCode=Type.GetTypeCode(properties.PropertyType)


很抱歉耽搁了,我把你的代码样本弄乱了。这就成功了,谢谢!设置“null”时,它不起作用。它很容易修复,尝试编辑您的帖子,但遭到拒绝。@PranayRana刚刚找到了这个解决方案,并将其应用到我遇到的一个问题中。工作得很好,我所做的唯一更改是将您的助手变成扩展。这在GUID上也有奇怪的中断。对于targetType,我使用这种方法:var targetType=Nullable.GetUnderlyingType(propType)??固有型;我怀疑是这样的,谢谢你的解释。我正在寻找如何转换为enum。谷歌把我带到这个页面,所以我很高兴你插话!!!工作起来很有魅力。
switch (typeCode)
{
  case TypeCode.Int32:
  properties.SetValue(m, Convert.ToInt32(value.AsPrimitive().Value));
  break;
  case TypeCode.Int64:
  properties.SetValue(m, Convert.ToInt64(value.AsPrimitive().Value));
  break;
}