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