Как получить значение частного поля в С#?

У меня возникла проблема, с которой мне нужно получить доступ к закрытому полю класса. Например:

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 что-то похоже на "поиск значения свойства с отражением С#".