31

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

reflectionプロパティを直接設定すると機能するのに、プロパティを設定すると機能しないのはなぜですか?

4

8 に答える 8

77

記事全体を確認してください: リフレクションを使用してプロパティの値を設定する方法は?

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

このように値を変換する必要があります。つまり、以下のように値をプロパティ タイプに変換する必要があります。

PropertyInfo info = t.GetProperty("Value");
object value = null;
try 
{ 
    value = System.Convert.ChangeType(123, 
        Nullable.GetUnderlyingType(info.PropertyType));
} 
catch (InvalidCastException)
{
    return;
}
propertyInfo.SetValue(obj, value, null);

任意の値を特定の型に変換できないため、これを行う必要があります...したがって、このように変換する必要があります

于 2012-11-07T12:59:39.367 に答える
4

あなたが書くとき:

obj.Value = v;

コンパイラは適切なキャストを行う方法を知っており、実際にコンパイルします

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

リフレクションを使用する場合、役立つコンパイラはありません。

于 2012-11-07T13:01:06.960 に答える
2

longには暗黙的な変換メソッドがあるためです。

6.1.2 暗黙の数値変換

=暗黙的な変換メソッドは、シンボルの背後にある隠しメソッドとして表示できます。

null 許容型でも機能します。

int i = 0;
int? j = i; // Implicit conversion
long k = i; // Implicit conversion
long? l = i; // Implicit conversion

nullただし、a を非 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.

intaを a int?... または aに明示的に変換する必要はありませんlong?

ただし、リフレクションを使用すると、暗黙的な変換がバイパスされ、値がプロパティに直接割り当てられます。このように、明示的に変換する必要があります。

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

リフレクションは、後ろに隠れているすべての甘いものをスキップします=

于 2012-11-07T13:01:43.303 に答える
2

SilverNinjaによって提案された(およびthecoopによって回答された) sを処理するためのPranay Ranaの回答を統合および拡張し、学習を 1 か所に蓄積しました。これはもう少しコピー/貼り付け可能です。;enum

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<>));
}
于 2018-03-20T16:39:51.693 に答える
0

double への変換のために私のために働いたこのようなものを試すことができますか?:

Type propType = propInfo.PropertyType;

if (propType.AssemblyQualifiedName.StartsWith("System.Nullable`1[[System.Double"))
{
    if (dataRow[column.ColumnName] == DBNull.Value)
    {
        propInfo.SetValue(obj, null, null);
    }
    else
        propInfo.SetValue(obj, (double?)dataRow[column.ColumnName], null);
}
else
    propInfo.SetValue(obj, dataRow[column.ColumnName], null);
于 2021-11-16T05:58:59.060 に答える
0

var プロパティ = propTypes.GetProperty(属性);

TypeCode typeCode = Type.GetTypeCode(properties.PropertyType);

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;
}
于 2021-02-15T13:46:56.807 に答える
0

これは古いスレッドです。しかし、このページの解決策はうまくいきませんでした。私はいくつかの調整を行い、うまく機能しました(.netcore 2.0で)!

obj = Activator.CreateInstance<T>();
foreach (PropertyInfo prop in obj.GetType().GetProperties())
{
    if (!object.Equals(this.reader[prop.Name], DBNull.Value))
    {
        if (prop.PropertyType.Name.Contains("Nullable"))
        {
            prop.SetValue(obj, Convert.ChangeType(this.reader[prop.Name], Nullable.GetUnderlyingType(prop.PropertyType)), null);
        }
        else
        {
            prop.SetValue(obj, this.reader[prop.Name], null);
        }
    }
}
于 2020-04-24T14:21:19.020 に答える