简体   繁体   English

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

[英]c# generic type class cannot get the property value

Using c# reflection to get & set the value of the generic fields inside a generic object. 使用c#reflection来获取和设置泛型对象中的通用字段的值。 But I cannot find any way to get the property value of these fields . 但我找不到任何方法来获得这些字段的属性值 The code example below: 下面的代码示例:

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

Problem Getting the 'null' item at the line (*). 问题在行(*)处获取“null”项。

itemField.GetType() always return the System.Reflection.RtFieldInfo type but not the Foo type. itemField.GetType()始终返回System.Reflection.RtFieldInfo类型,但不返回Foo类型。

I already tried using itemField.FieldType.GetProperty("IsUpdated"), it worked when returned the correct property. 我已经尝试过使用itemField.FieldType.GetProperty(“IsUpdated”),它在返回正确的属性时起作用。 But threw an error "Object does not match target type." 但抛出错误“对象与目标类型不匹配”。 whenever call GetValue() method itemField.FieldType.GetProperty("IsUpdated").GetValue(itemField, null) 每次调用GetValue()方法itemField.FieldType.GetProperty(“IsUpdated”)。GetValue(itemField,null)

Much more appreciated if getting help from anyone! 如果得到任何人的帮助,我们将非常感激!

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

let's unpack this one thing at a time: 让我们一次解开这一件事:

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

You should never need to use .GetType() on a member; 永远不需要在成员上使用.GetType() ; you want .FieldType or .PropertyType (for properties). 你想.FieldType.PropertyType (房产)。 And nameof is great: 并且nameof很棒:

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

( string here is a dummy) (这里的string是假的)

Then: 然后:

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

It isn't itemField that is your object - that's whatever the value of itemField on that object gives you. itemField不是你的对象 - 这就是该对象itemField的值给你的东西。 So pass that in; 所以通过; and treat the result as a boolean , if possible: 如果可能的话,将结果视为布尔值

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

Finally: 最后:

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

Once again, the object is itemList , and the property isn't a string 对象再次是itemList ,属性不是string

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

It would be easier if you made Foo<T> : IFoo where IFoo is a non-generic interface: 如果你做了Foo<T> : IFoo ,其中IFoo是一个非通用接口会更容易:

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

Then it becomes: 然后它变成:

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

Finally, note that FirstName and LastName will be null if you haven't assigned them anything. 最后,请注意,如果您没有为它们指定任何内容, FirstNameLastName 将为null

You must use the FieldType property instead of GetType() at itemField to get Foo type. 您必须在itemField使用FieldType属性而不是GetType()来获取Foo类型。

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

EDIT: You must get the instance of the field type 编辑:您必须获取字段类型的实例

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

Final result should be like this: 最终结果应该是这样的:

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

Let me throw my two cents on trying to give you another point of view to solve the problem. 让我把两分钱放在试图给你另一个观点来解决问题上。

I wouldn't use reflection for this: why don't you type those objects with interfaces? 我不会为此使用反射 :为什么不用接口键入这些对象?

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()

I'm not sure if I've caught the idea, but it seems like you're overengineering and bypassing typing for no reason! 我不确定我是否已经抓住了这个想法,但似乎你是过度工程并且无缘无故地绕过打字!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM