c# 泛型类型 class 无法获取 属性 值

c# generic type class cannot get the property value

使用 C# 反射获取和设置通用对象内通用字段的值。但是我找不到任何方法来 获取这些字段的 属性 值 。下面的代码示例:

public class Foo<T>
{
   public bool IsUpdated { get; set; } 
}

public abstract class ValueObjec<T>
{
   public string InnerValue { get; set; } 
}

public class ItemList: ValueObject<ItemList>
{
   public Foo<string> FirstName;

   public Foo<string> LastName;
}

问题 在 (*) 行获取 'null' 项目。

itemField.GetType() 总是 return System.Reflection.RtFieldInfo 类型而不是 Foo 类型.

我已经尝试使用 itemField.FieldType.GetProperty("IsUpdated"),当 return 编辑正确的 属性 时它起作用了。但是每当调用 GetValue() 方法时都会抛出错误 "Object does not match target type." itemField.FieldType.GetProperty("IsUpdated").GetValue(itemField, null)

如果能得到任何人的帮助,将不胜感激!

var itemList = new ItemList();
foreach (var itemField in itemList.GetType().GetFields())
{
    var isUpdated = "false";
    var isUpdatedProp = itemField.GetType().GetProperty("IsUpdated"); // (*) return null from here
    if (isUpdatedProp != null)
    {
        isUpdated = isUpdatedProp.GetValue(itemField, null).ToString();
        if (isUpdated == "false") isUpdatedProp.SetValue(itemField, "true");
    }
}

foreach (var itemField in itemList.GetType().GetFields())
        {
            var isUpdated = "false";
            var isUpdatedProp = itemField.FieldType.GetProperty("IsUpdated");
            if (isUpdatedProp != null)
            {
                isUpdated = isUpdatedProp.GetValue(itemField, null).ToString(); (*) // throw error "Object does not match target type"
                if (isUpdated == "false") isUpdatedProp.SetValue(itemField, "true");
            }
        }

您必须在 itemField 处使用 FieldType 属性 而不是 GetType() 才能获得 Foo 类型。

https://msdn.microsoft.com/en-us/library/system.reflection.fieldinfo.fieldtype(v=vs.110).aspx

编辑: 您必须获取字段类型的实例

var foo = itemField.GetValue(itemList);
var isUpdated = isUpdatedProp.GetValue(foo);

最终结果应该是这样的:

var itemList = new ItemList();
foreach (var itemField in itemList.GetType().GetFields())
{
    var isUpdatedProp = itemField.FieldType.GetProperty("IsUpdated"); 
    if (isUpdatedProp != null)
    {
        var foo = itemField.GetValue(itemList);
        isUpdated = (bool)isUpdatedProp.GetValue(foo);
        if (!isUpdated) isUpdatedProp.SetValue(foo, true);
    }
}

让我们一次打开这个东西:

var isUpdatedProp = itemField.GetType().GetProperty("IsUpdated");

您应该从不需要对成员使用.GetType();你想要 .FieldType.PropertyType(对于属性)。 nameof 很棒:

var isUpdatedProp = itemField.FieldType.GetProperty(nameof(Foo<string>.IsUpdated));

(string 这里是一个假人)

然后:

 isUpdated = isUpdatedProp.GetValue(itemField, null).ToString();

它不是 itemField 那是你的对象 - 那是 itemField 在那个对象 上给你的任何值。所以把它传进去;并将结果 视为布尔值 ,如果可能的话:

var isUpdated = false;
object foo = itemField.GetValue(itemList);
...
isUpdated = (bool)isUpdatedProp.GetValue(foo, null);

最后:

if (isUpdated == "false") isUpdatedProp.SetValue(itemField, "true");

再次强调,对象是 itemList,属性 不是 string

if (!isUpdated) isUpdatedProp.SetValue(foo, true);

如果你制作 Foo<T> : IFoo 会更容易,其中 IFoo 是一个 non-generic 接口:

interface IFoo { bool IsUpdated {get; set; } }

然后变成:

var foo = (IFoo)itemField.GetValue(itemList);
if(!foo.IsUpdated) foo.IsUpdated = true;

最后,请注意 FirstNameLastName 如果您没有为它们分配任何内容,它们将是 null

让我花两分钱尝试为您提供解决问题的另一种观点。

我不会为此使用 反射:你为什么不用接口来键入那些对象?

public interface IUpdatable
{
     bool IsUpdated { get; set; }
}

public interface IManyUpdatable 
{
     IEnumerable<IUpdatable> Updatables { get; }
}

public static class UpdatableExtensions 
{
     public static void ToggleUpdated(this IUpdatable updatable) 
     {
          if(updatable != null)
               updatable.IsUpdated = !updatable.IsUpdated
     }

     public static void ToggleUpdatables(this IEnumerable<IUpdatable> updatables)
     {
          foreach(var updatable in updatables) 
                 updatable.ToggleUpdated()

     }
}

public class Foo<T> : IUpdatable
{
   public bool IsUpdated { get; set; }
}

public class ItemList: ValueObject<ItemList>
{
   public Foo<string> FirstName;

   public Foo<string> LastName;

   IEnumerable<IUpdatable> IManyUpdatable.Updatables => new [] {  FirstName, LastName }
}

// ... somewhere in your code base:

itemList.ToggleUpdatables()

我不确定我是否理解了这个想法,但您似乎过度设计并无缘无故地绕过了打字!