В большинстве случаев доступ к закрытым (private) членам класса из вне не требуется и более того в силу целого ряда объективных причин получать его не рекомендуется. Однако в некоторых случаях это может быть полезным.
В C# существует два способа получить доступ к закрытым членам (не считая открытых методов и свойств). Это доступ из вложенного класса и рефлексия.
В рамках данной статьи мы рассмотрим только доступ к полям и свойствам. Вызов закрытых методов будет рассмотрен отдельно.
Использование вложенных классов
В C# во вложенном классе в можно получить доступ к закрытым членам экземпляра внешнего класса, а также его статическим членам. В то же время доступ к закрытым членам вложенного класса из внешнего класса невозможен.
Пример:
class TestClass
{
private int testField;
private string TestString { get; set; }
private static string TestStringStatic { get; set; }
class TestInnerClass
{
public void TestMethod()
{
TestClass.TestString2 = "abcdef";
TestClass tc = new();
tc.testField = 1;
tc.TestString = "ABCDEF";
}
public void TestMethod2(TestClass tc)
{
TestClass.TestString2 = "abcdef";
tc.testField = 1;
string s = tc.TestString;
tc.TestString = "ABCDEF";
}
}
}
Данный подход в силу своего архитектурного решения далеко не всегда удобен. Но, есть альтернатива в виде рефлексии.
Рефлексия
Рефлексия позволяет получать описание типов данных во время выполнения программы. Что в свою очередь даёт возможность получить доступ к закрытым членам. В данном случае к полям и методам.
Доступ к полям осуществляется при помощи класса FieldInfo. Для примера используем класс приведённый ранее.
TestClass tc = new();
// Получаем дотсуп к полю по его имени.
FieldInfo fieldInfo = typeof(TestClass).GetField("testField",BindingFlags.NonPublic|BindingFlags.Instance);
// Устанавливаем значение поля.
fieldInfo.SetValue(tc, 5);
// Получаем значение поля.
int a = (int)fieldInfo.GetValue(tc);
Обратите внимание на флаги BindingFlags.NonPublic (член класса private, internal или protected) и BindingFlags.Instance (член класса не является статическим). Эти флаги необходимо обязательно передавать в метод GetField и притом совместно. Иначе доступ к полю не будет установлен.
Доступ к закрытому свойству при помощи класса PropertyInfo осуществляется аналогичным образом.
TestClass tc = new();
// Получение доступа к свойству по имени.
PropertyInfo propertyInfo = typeof(TestClass).GetProperty("TestString", BindingFlags.NonPublic | BindingFlags.Instance);
// Устанавливаем значение свойства получаем значение свойства.
propertyInfo.SetValue(tc, "ABCDEF");
//Получаем значение свойства.
string s = (string)propertyInfo.GetValue(tc);
Если закрытое поле или свойство являются статическими, то нужно просто заменить флаг BindingFlags.Instance на BindingFlags.Static.
Пример для статического свойства:
PropertyInfo propertyInfo = typeof(TestClass).GetProperty("TestStringStatic", BindingFlags.NonPublic | BindingFlags.Static);