.net 是否可以通过反射设置私有属性?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1565734/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to set private property via reflection?
提问by AwkwardCoder
Can I set a private property via reflection?
我可以通过反射设置私有属性吗?
public abstract class Entity
{
private int _id;
private DateTime? _createdOn;
public virtual T Id
{
get { return _id; }
private set { ChangePropertyAndNotify(ref _id, value, x => Id); }
}
public virtual DateTime? CreatedOn
{
get { return _createdOn; }
private set { ChangePropertyAndNotify(ref _createdOn, value, x => CreatedOn); }
}
}
I've tried the following and it does not work, where trepresents a type of Entity:
我尝试了以下方法但它不起作用,其中t代表一种类型Entity:
var t = typeof(Entity);
var mi = t.GetMethod("set_CreatedOn", BindingFlags.Instance | BindingFlags.NonPublic);
I guess I can do this but I can't work it out.
我想我可以做到这一点,但我无法解决。
采纳答案by Tinister
t.GetProperty("CreatedOn")
.SetValue(obj, new DateTime(2009, 10, 14), null);
EDIT: Since the property itself is public, you apparently don't need to use BindingFlags.NonPublicto find it. Calling SetValuedespite the the setter having less accessibility still does what you expect.
编辑:由于该属性本身是公开的,您显然不需要使用BindingFlags.NonPublic它来查找它。SetValue尽管 setter 的可访问性较低,但调用仍然可以满足您的期望。
回答by Arthur
Yes, it is:
是的:
/// <summary>
/// Returns a _private_ Property Value from a given Object. Uses Reflection.
/// Throws a ArgumentOutOfRangeException if the Property is not found.
/// </summary>
/// <typeparam name="T">Type of the Property</typeparam>
/// <param name="obj">Object from where the Property Value is returned</param>
/// <param name="propName">Propertyname as string.</param>
/// <returns>PropertyValue</returns>
public static T GetPrivatePropertyValue<T>(this object obj, string propName)
{
if (obj == null) throw new ArgumentNullException("obj");
PropertyInfo pi = obj.GetType().GetProperty(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (pi == null) throw new ArgumentOutOfRangeException("propName", string.Format("Property {0} was not found in Type {1}", propName, obj.GetType().FullName));
return (T)pi.GetValue(obj, null);
}
/// <summary>
/// Returns a private Property Value from a given Object. Uses Reflection.
/// Throws a ArgumentOutOfRangeException if the Property is not found.
/// </summary>
/// <typeparam name="T">Type of the Property</typeparam>
/// <param name="obj">Object from where the Property Value is returned</param>
/// <param name="propName">Propertyname as string.</param>
/// <returns>PropertyValue</returns>
public static T GetPrivateFieldValue<T>(this object obj, string propName)
{
if (obj == null) throw new ArgumentNullException("obj");
Type t = obj.GetType();
FieldInfo fi = null;
while (fi == null && t != null)
{
fi = t.GetField(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
t = t.BaseType;
}
if (fi == null) throw new ArgumentOutOfRangeException("propName", string.Format("Field {0} was not found in Type {1}", propName, obj.GetType().FullName));
return (T)fi.GetValue(obj);
}
/// <summary>
/// Sets a _private_ Property Value from a given Object. Uses Reflection.
/// Throws a ArgumentOutOfRangeException if the Property is not found.
/// </summary>
/// <typeparam name="T">Type of the Property</typeparam>
/// <param name="obj">Object from where the Property Value is set</param>
/// <param name="propName">Propertyname as string.</param>
/// <param name="val">Value to set.</param>
/// <returns>PropertyValue</returns>
public static void SetPrivatePropertyValue<T>(this object obj, string propName, T val)
{
Type t = obj.GetType();
if (t.GetProperty(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) == null)
throw new ArgumentOutOfRangeException("propName", string.Format("Property {0} was not found in Type {1}", propName, obj.GetType().FullName));
t.InvokeMember(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty | BindingFlags.Instance, null, obj, new object[] { val });
}
/// <summary>
/// Set a private Property Value on a given Object. Uses Reflection.
/// </summary>
/// <typeparam name="T">Type of the Property</typeparam>
/// <param name="obj">Object from where the Property Value is returned</param>
/// <param name="propName">Propertyname as string.</param>
/// <param name="val">the value to set</param>
/// <exception cref="ArgumentOutOfRangeException">if the Property is not found</exception>
public static void SetPrivateFieldValue<T>(this object obj, string propName, T val)
{
if (obj == null) throw new ArgumentNullException("obj");
Type t = obj.GetType();
FieldInfo fi = null;
while (fi == null && t != null)
{
fi = t.GetField(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
t = t.BaseType;
}
if (fi == null) throw new ArgumentOutOfRangeException("propName", string.Format("Field {0} was not found in Type {1}", propName, obj.GetType().FullName));
fi.SetValue(obj, val);
}
回答by Siarhei Kuchuk
You can access private setter from derived type via code
您可以通过代码从派生类型访问私有 setter
public static void SetProperty(object instance, string propertyName, object newValue)
{
Type type = instance.GetType();
PropertyInfo prop = type.BaseType.GetProperty(propertyName);
prop.SetValue(instance, newValue, null);
}
回答by CZahrobsky
None of these worked for me, and my property name was unique, so I just used this:
这些都不适合我,而且我的属性名称是唯一的,所以我只使用了这个:
public static void SetPrivatePropertyValue<T>(T obj, string propertyName, object newValue)
{
// add a check here that the object obj and propertyName string are not null
foreach (FieldInfo fi in obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
{
if (fi.Name.ToLower().Contains(propertyName.ToLower()))
{
fi.SetValue(obj, newValue);
break;
}
}
}
回答by BTE
//mock class
public class Person{
public string Name{get; internal set;}
}
// works for all types, update private field through reflection
public static T ReviveType<T>(T t, string propertyName, object newValue){
// add a check here that the object t and propertyName string are not null
PropertyInfo pi = t.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
pi.SetValue(t, newValue, null);
return t;
}
// check the required function
void Main()
{
var p = new Person(){Name="John"};
Console.WriteLine("Name: {0}",p.Name);
//box the person to object, just to see that the method never care about what type you pass it
object o = p;
var updatedPerson = ReviveType<Object>(o, "Name", "Webber") as Person;
//check if it updated person instance
Console.WriteLine("Name: {0}",updatedPerson.Name);
}
// Console Result: -------------------
Name: John
Name: Webber

