Как получить значение частного поля в С#?
У меня возникла проблема, с которой мне нужно получить доступ к закрытому полю класса. Например:
class MyClass
{
private string someString;
public MyClass( string someStringValue )
{
someString = someStringValue;
}
}
Как я могу получить значение someString вне MyClass?
Обновление:
Извините, я не могу использовать свойство здесь, так как фактический производственный код защищен. Я QA/Dev, мне нужен способ, чтобы частные пользователи писали User Acceptance Test. Поэтому я не могу изменить производственный код. Вы можете помочь?
Ответы
Ответ 1
Как говорили другие, поскольку поле является частным, вы не должны пытаться получить его с помощью обычного кода.
Единственное время, когда это приемлемо, - это во время модульного тестирования, и даже тогда вам нужна веская причина сделать это (например, чтобы установить приватную переменную в null, чтобы код в блоке исключений попал и может быть протестирован).
Чтобы получить поле, вы можете использовать что-то вроде метода ниже:
/// <summary>
/// Uses reflection to get the field value from an object.
/// </summary>
///
/// <param name="type">The instance type.</param>
/// <param name="instance">The instance object.</param>
/// <param name="fieldName">The field name which is to be fetched.</param>
///
/// <returns>The field value from the object.</returns>
internal static object GetInstanceField(Type type, object instance, string fieldName)
{
BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
| BindingFlags.Static;
FieldInfo field = type.GetField(fieldName, bindFlags);
return field.GetValue(instance);
}
Итак, вы могли бы назвать это следующим:
string str = GetInstanceField(typeof(YourClass), instance, "someString") as string;
Опять же, это не должно использоваться в большинстве случаев.
Ответ 2
Вы не можете - и вы не должны. Это личное. Если это кто-то другой класс, то ясно, что они не хотят, чтобы у вас был доступ к этому полю. Тот факт, что он закрыт, позволяет им позже изменить реализацию - они могут оказаться в этой переменной как часть другой переменной или переименованы или, возможно, полностью исчезли, если она больше не требуется для реализации публичного API.
Если это ваш собственный класс, и вы уверены, что хотите, чтобы другие люди могли получить к нему доступ, просто выставьте его с помощью свойства:
public string SomeString { get { return someString; } }
EDIT: увидев ваши комментарии, вы можете получить доступ к закрытым полям с отражением... но для приемочного теста вам не придется этого делать. Вы должны тестировать открытый API. Для модульных тестов имеет смысл иногда изгибать правила и относиться к классу как к "белой коробке", а не к тестированию "черного ящика", но для приемочных тестов я определенно придерживаюсь общедоступного API.
Если это не помогает, я предлагаю вам поговорить с разработчиками производственного кода: объясните, почему вы хотите получить доступ, и попросите их разоблачить его через свойство. Они могут сделать это внутренним свойством и использовать [InternalsVisibleTo]
, чтобы получить доступ к нему в тестовой сборке. Я лично предпочел бы это, используя рефлексию - в противном случае, если производственный код будет изменяться совершенно корректно, ваши тесты потерпят неудачу, когда они не должны.
Ответ 3
Используйте отражения, но будьте готовы к удару с помощью большой палочки от другого программиста.
Ответ 4
Если это вы класс, и вы хотите предоставить ему доступ за пределами класса, разоблачите его через общедоступное свойство:
public string SomeString { get { return someString; } }
В противном случае не используйте его вне класса. Вы не должны.
ИЗМЕНИТЬ
На основании вашего комментария, что вы на самом деле выполняете QA-тестирование производственного кода, я бы поставил под сомнение обоснование необходимости доступа к личным значениям во время тестирования. Вам действительно нужно только проверять публично открытые свойства/методы, чтобы убедиться, что все работает по назначению.
Все, что сказано, если вокруг нет вещей, которые вы можете использовать Reflection для получения значений.
Ответ 5
Вы можете использовать этот метод расширения.
public static class Extensions
{
public static object GetFieldValue(this object instance, string fieldName)
{
const BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
var field = instance.GetType().GetField(fieldName, bindFlags);
return field == null ? null : field.GetValue(instance);
}
}
Ответ 6
Если вы используете его для модульного тестирования, я внедрил общую версию ответа @dcp, которая предоставляет следующие дополнительные функции:
- Указывает, существует ли поле
- Задает, если значение имеет тип "T".
- Преобразует значение в тип "T".
код:
private const BindingFlags BindFlags = BindingFlags.Instance
| BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Static;
/// <summary>
/// Uses reflection to get the field value from an object.
/// </summary>
/// <param name="type">The instance type.</param>
/// <param name="instance">The instance object.</param>
/// <param name="fieldName">The field name which is to be fetched.</param>
/// <returns>An instance of <see cref="T"/>.</returns>
internal static T GetInstanceField<T>(Type type, object instance, string fieldName)
{
var field = type.GetField(fieldName, BindFlags);
Assert.IsNotNull(field, string.Format("The field with name '{0}' does not exist in type '{1}'.", fieldName, type));
var value = field.GetValue(instance);
Assert.IsInstanceOfType(value, typeof(T), string.Format("The value of the field '{0}' is not of type '{1}'", fieldName, typeof(T)));
return (T)value;
}
Ответ 7
в дополнение к @dcp answer, это может быть намного проще, превратив его в Generic Function...
internal static T GetInstanceField<T>(object instance, string fieldName)
{
BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
| BindingFlags.Static;
FieldInfo field = type.GetField(fieldName, bindFlags);
return field.GetValue(instance);
}
Ответ 8
Сделать общедоступной собственность
public string SomeString {get; private set;}
Это объявление свойства позволит любому внешнему классу читать переменную, но не изменять ее (следовательно, частный "сеттер" ).
РЕДАКТИРОВАТЬ: просто посмотрел ваш комментарий на другой ответ. Вам придется использовать Relection, чтобы получить такую приватную переменную. И как в другом предложенном ответе, обязательно следите за программистами с помощью палочек;). Тем не менее, Google что-то похоже на "поиск значения свойства с отражением С#".