I want to be able to access a property or member of a class by name. I'm fine if it's a property:
PropertyInfo prop = object.GetType().GetProperty(propertyName);
object propValue = prop.GetValue(object, null);
Things seem a little tric开发者_如何学Pythonkier if it is a member/field. AFter studying GetMember
and trying a bunch of different stuff I can't figure out how to just get a reference to the object the same way it would be returned from GetProperty
, if it was a property.
The other question is, is this the right way to accomplish this? In reading about reflection, it seems to have a lot of overhead. Is this just in comparison to not using reflection, or is it significant enough that I should think twice about developing something that will be doing this a lot, and what alternatives do I have, if any, to obtain a reference to a member of a class by name only?
Thanks for any insight. If it makes any difference, my goal is to be able to serialize an arbitrary named property or member of a class.
You can use GetField instead of GetProperty
if you want to retrieve a field.
FieldInfo field = object.GetType().GetField(fieldName);
object fieldValue = field.GetValue(Context.Parent);
or is it significant enough that I should think twice about developing something that will be doing this a lot, and what alternatives do I have, if any, to obtain a reference to a member of a class by name only?
It is definitely expensive, but I'd profile it to determine if you will have a performance issue.
The other main option(s) is to build some form of dictionary yourself that maps "names" to values. This can be a direct dictionary mapping to the value, or a dictionary that maps to a delegate which retrieves the value. This does have the advantage in that you can make it work the same way for properties or fields, but each class needs to create the mapping. (This can, however, potentially be done via reflection at construction time.)
If it makes any difference, my goal is to be able to serialize an arbitrary named property or member of a class.
I would recommend reviewing the built-in Serialization Support prior to rolling your own version...
If you're using C# 4.0 (released alongside the .NET Framework 4.0 and Visual Studio 2010), there's the new dynamic
keyword that will simplify things in your code:
dynamic myValue = anyObject;
string name = myValue.myField; // Resolved at runtime, not compile-time
bool result = myValue.myBooleanMethod(1, 2, 3); // Ditto
etc. My understanding is that this does more-or-less the same thing under the hood as using reflection and testing for the existence of compatible PropertyInfo
/MethodInfo
/etc. and then invoking them, so performance is still a concern, but it's certainly a lot more readable.
What I came up with for caching, comments welcome.
public static ConcurrentDictionary<Tuple<Type, string>,
Func<object, object[], object>> ReflectionCache
{
get
{
if (_ReflectionCache==null) {
_ReflectionCache = new ConcurrentDictionary<Tuple<Type, string>,
Func<object, object[], object>>();
}
return _ReflectionCache;
}
} private static ConcurrentDictionary<Tuple<Type, string>,
Func<object, object[], object>> _ReflectionCache = null;
public static object GetCachedProperty(object obj, string name)
{
Func<object,object[],object> del;
if (!ReflectionCache.TryGetValue(Tuple.Create<Type,string>(obj.GetType(),
name), out del)) {
MemberInfo memberInfo =
(MemberInfo)obj.GetType().GetMember(name).GetValue(0);
PropertyInfo prop = null;
FieldInfo fld = null;
switch(memberInfo.MemberType) {
case MemberTypes.Field:
fld = obj.GetType().GetField(name);
break;
case MemberTypes.Property:
prop = obj.GetType().GetProperty(name);
break;
}
if (prop == null && fld == null)
{
throw new Exception("No property or field named '" + name
+ "' could be found in the context parent.");
}
if (prop!=null) {
prop= obj.GetType().GetProperty(name);
del = prop.GetValue;
} else {
fld = obj.GetType().GetField(name);
del = delegate(object cls,object[] index) {
return fld.GetValue(cls);
};
}
ReflectionCache[Tuple.Create<Type,string>(obj.GetType(),name)]=del;
}
return(del(obj,null));
}
精彩评论