在C#里,类的私有变量和私有方法默认只能在类内部访问。但借助反射机制,我们可以在运行时绕过编译期访问限制,读取或修改这些非公开成员。反射主要通过System.Reflection命名空间下的Type、FieldInfo、MethodInfo等类型来实现。
一、使用反射修改私有变量
假设有一个类,里面包含一个私有字段,我们希望在外部把它改掉。下面先看这个类的定义:
using System;
public class User
{
private string name = "default";
public void Show()
{
Console.WriteLine("name: " + name);
}
}
接着,我们在另一个地方通过反射修改它的私有字段 name:
using System;
using System.Reflection;
class Program
{
static void Main()
{
User user = new User();
user.Show();
// 获取类型
Type type = typeof(User);
// 获取私有字段,BindingFlags.NonPublic表示非公开,Instance表示实例成员
FieldInfo field = type.GetField("name", BindingFlags.NonPublic | BindingFlags.Instance);
if (field != null)
{
// 修改私有变量的值
field.SetValue(user, "changed_by_reflection");
}
user.Show();
}
}
运行后可以看到,第一次输出是默认值,第二次已经变成了我们通过反射设置的新值。
二、访问私有方法
除了字段,私有方法也能用反射调用。给 User 类加一个私有方法:
using System;
public class User
{
private void Secret()
{
Console.WriteLine("私有方法被调用");
}
}
外部调用的代码如下:
using System;
using System.Reflection;
class Program
{
static void Main()
{
User user = new User();
Type type = typeof(User);
MethodInfo method = type.GetMethod("Secret", BindingFlags.NonPublic | BindingFlags.Instance);
if (method != null)
{
method.Invoke(user, null);
}
}
}
三、注意事项
- 反射会跳过访问修饰符检查,但可能破坏封装性,生产环境要谨慎使用。
- 如果字段或方法是静态的,BindingFlags里要加上 Static 而不是 Instance。
- Silverlight、iOS 等部分平台对反射有限制,可能无法访问私有成员。
- 反射性能比直接调用低,不要在高频循环里频繁使用。
通过上述方式,我们就能用C#反射来修改私有变量以及访问类的非公开成员了。