C# 从设置的对象获取字段

C# 从设置的对象获取字段,c#,generics,reflection,C#,Generics,Reflection,我有以下结构: public struct UserProp<T> { private T val; public string Name { get; set; } public T Value { get { return (T) this.val; } set { this.val= value;

我有以下结构:

 public struct UserProp<T>
{
    private T val;
    public string Name { get; set; }

    public T Value
    {
        get
        {
            return (T) this.val;
        }
        set
        {
            this.val= value;
            this.IsSet = true;
        }
    }

    public bool IsSet;


}
以及使用它的类:

public class MyClass
{
     private UserProp<string> FirstName;
     private UserProp<int> ID;
     ....
}

如何获得IsSet为真的对象的所有字段?我打算使用反射并将GetField值转换为UserProp,但我不知道泛型的类型。本质上,我所要寻找的是:获取MyClass类型的UpServer的所有字段,不管IsSube是真的泛型类型。

< P>除非你有非常好的理由使用Stutt考虑为你的UpRop切换到类。这样,您就可以拥有用于共享属性的基类:

public class UserProp
{
   public string Name { get; set; }
   public bool IsSet { get; set; }
}

public class UserProp<T> : UserProp
{
   private T val;
   public T Value...
}

这样,您只需在字段上进行反射,并检查已知的UserProp类型和值,即可在强制转换后直接访问,而无需再进行一次反射,即可按名称获取值。

如果您不介意使用dynamic关键字,则此操作应能起作用:

static void Main(string[] args)
    {
        MyClass myclass = new MyClass();
        var type = myclass.GetType();
        var fields = type.GetFields().Where(x => x.FieldType != null && x.FieldType.Name == "UserProp`1");

        foreach (var item in fields)
        {
            dynamic userProp = item.GetValue(myclass);
            Console.WriteLine(userProp.IsSet);
        }

        myclass.FirstName.Value = "Mark";

        foreach (var item in fields)
        {
            dynamic userProp = item.GetValue(myclass);
            Console.WriteLine(userProp.IsSet);
        }

        Console.ReadLine();
    }
但我不知道泛型的类型

你不需要知道t是什么。使用开放泛型类型。下面是一个正确的例子:

var myClass = new MyClass();

foreach (var fieldInfo in myClass.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
{
    var fieldType = fieldInfo.FieldType;

    if (!fieldType.IsGenericType ||
        fieldType.GetGenericTypeDefinition() != typeof (UserProp<>))
    {
        Console.WriteLine("Ignoring {0} {1}", fieldType.Name, fieldInfo.Name);
        continue;
    }

    var fieldValue1 = fieldInfo.GetValue(myClass);
    var fieldInfo2 = fieldValue1.GetType().GetField("IsSet");
    var fieldValue2 = fieldInfo2.GetValue(fieldValue1);

    Console.WriteLine("{0}.IsSet has a value of {1}", fieldInfo.Name, fieldValue2);

    // You can check fieldValue2 and if true you now have "[a field] of
    // MyClass of type UserProp (regardless of generic type) where IsSet
    // is true". Loop until you get them all!
}
将产生以下结果:

Ignoring Int32 z
FirstName.IsSet has a value of False
ID.IsSet has a value of True

我必须指出,在那个类中有一个递归属性。这可能会导致StackOverflowException..谢谢,真正的对象有firstname、lastname等。我只是想简明扼要。谢谢你指出,我已经修好了。不,那是不正确的。在值的setter中设置this.Value将使其进入无限循环。您需要一个专用的支持字段。感谢您捕捉到Simon,为我以后节省了大量调试时间。这样您就可以将基类用于共享属性。结构可以实现接口。只需在上面放一个接口。@ta.speot.is-good point-interface是OP想要坚持使用struct的一个选项。我个人会避免使用struct,尤其是像OP这样的可变结构,因为它是值类型,并且通常会让试图访问/更改这种类型的值的人感到困惑。恐怕更改此结构包装属性的代码必须仔细检查,以避免修改字段的副本而不是原始副本…谢谢Alexei,我使用struct是因为我在活动内存中一次处理1000个employee对象,每个对象大约有40个属性是struct,我认为将值放在堆栈上而不是堆上的好处将提高性能。@Mike-我强烈建议在做出性能决策时进行度量,而不是思考。也就是说,你对反射没问题,这意味着你在每次访问IsSet时都会装箱你的结构,每次都会强制在堆上创建新对象…@Mike我认为在堆栈上而不是堆上有值的好处会提高性能+1注意,如果UserProp是struct,那么这段代码会强制每次访问字段。像往常一样,如果发现代码太慢,反射可以被缓存,甚至转换成和编译。@AlexeiLevenkov+1我必须承认,我在脑海中读到了你的第一句话,然后想,这是不可避免的,但你对编译表达式的看法是对的。
Ignoring Int32 z
FirstName.IsSet has a value of False
ID.IsSet has a value of True