Comments 27
Вы переусложнили GetSecretUsingExpressionTrees, в этом случае достаточно такого:
public static int GetSecretUsingExpressionTrees(this SecretKeeper keeper)
{
ParameterExpression keeperArg = Expression.Parameter(typeof(SecretKeeper), "keeper"); // SecretKeeper keeper argument
Expression secretAccessor = Expression.Field(keeperArg, "_secret"); // keeper._secret
var lambda = Expression.Lambda<Func<SecretKeeper, int>>(secretAccessor, keeperArg);
var func = lambda.Compile(); // Получается функция return result = keeper._secret;
return func(keeper);
}
Валидный путь раскрывать приватные поля без «хаков» это под-класс https://gist.github.com/deniszykov/556ddc0a1d335c96fb58b808ac66c894
Вы правы, nested классы видят поля внешних классов. При этом они довольно схожи с protected полями: также нужно создать дополнительный класс для доступа к секрету, также требуется изменить основной класс. Полагаю, область применения также совпадает.
Быстродействие, по идее, тоже одинаковое, но тут надо смотреть. Завтра замерю, выложу результаты.
В любом случае, спасибо за 5 способ.
Быстродействие, по идее, тоже одинаковое, но тут надо смотреть. Завтра замерю, выложу результаты.
В любом случае, спасибо за 5 способ.
Хм, 3 метод отказыватся работать на .NET 4.5. Не хочет выдавать он приватные поля. Тогда как для public работает как и задумывалось.
Только что проверил на 4, 4.5, 4.6 — все ок. VS 2015, AnyCPU, Debug.
Хм, проверял на .FiddleNet
Как варианты — full trusted code, или проблемы с динамическими библиотеками.
Если работает с public полями — полагаю, дело в partial trust.
Если работает с public полями — полагаю, дело в partial trust.
Вам не кажется, что задача немного надуманная: реализовывать доступ к приватному полю класса, если есть возможность модифицировать этот самый класс? В этом случае, всё решается public свойством/методом. В случае, когда такого доступа нет и поле действительно private, то единственный способ — это рефлексия в той или иной вариации (примеры 2 и 3 в вашей статье).
Бывают варианты.
У одной крупной мировой корпорации в коде для одного продукта была либа версии 5.0. В ней класс c двумя приватными полями. В версии 7.0 одно поле было публичным, а доступ к другому осуществляли через рефлексию. Возможность модификации есть, одного поля public нет, причины неизвестны.
Лично я однажды не мог изменять написанный мною же класс: он к тому времени функционировал уже три месяца, был полон г**нокода, и полностью подпадал под резолюцию «работает — не трогай».
У одной крупной мировой корпорации в коде для одного продукта была либа версии 5.0. В ней класс c двумя приватными полями. В версии 7.0 одно поле было публичным, а доступ к другому осуществляли через рефлексию. Возможность модификации есть, одного поля public нет, причины неизвестны.
Лично я однажды не мог изменять написанный мною же класс: он к тому времени функционировал уже три месяца, был полон г**нокода, и полностью подпадал под резолюцию «работает — не трогай».
1) Имхо, для тестов, способ 3 — самый годный. Плюс лямбда-геттер надо бы закэшировать.
Имхо, вложенный класс для раскрытия состояния (конкретно для тестовых случаев) — способ неправильный и нагружает класс лишним знанием о том, что кто-то должен будет к приватному члену обратиться. Лучше поправить упавшие тесты при рефакторинге приватного члена, на который тесты заточены, чем вносить лишнюю ответственность в класс.
2) Тестировать внутреннее состояние не совсем правильно, ибо по канонам ООП, класс должен обеспечивать корректную работу с внешней средой через публичный API. А как он это делает внутри — его личное дело.
Имхо, вложенный класс для раскрытия состояния (конкретно для тестовых случаев) — способ неправильный и нагружает класс лишним знанием о том, что кто-то должен будет к приватному члену обратиться. Лучше поправить упавшие тесты при рефакторинге приватного члена, на который тесты заточены, чем вносить лишнюю ответственность в класс.
2) Тестировать внутреннее состояние не совсем правильно, ибо по канонам ООП, класс должен обеспечивать корректную работу с внешней средой через публичный API. А как он это делает внутри — его личное дело.
Вопрос новичка:
А что означает эта строка:
protected int SecretForInheritors => _secret;
Точнее, оператор => в ней?
Это ведь лямбда-оператор?
А что означает эта строка:
protected int SecretForInheritors => _secret;
Точнее, оператор => в ней?
Это ведь лямбда-оператор?
А можно ссылку (или примерное название) на статью, упомянутую в первом абзаце? Я так понимаю, это фишка C#? Думается мне, что совместно с методами расширения довольно интересно можно расстрелять себе ноги.
Ноги расстрелять нельзя, т.к. методы расширения имеют доступ только к публичным членам
Не могу найти статью. Даже мой комментарий к ней пропал. Возможно, автор скрыл в черновики.
По поводу методов расширения — для того, чтобы метод видел эту переменную, он должен быть членом SecretKeeper (напрямую или в nested классе), так что для расстрельной ситуации придется постараться.
По поводу методов расширения — для того, чтобы метод видел эту переменную, он должен быть членом SecretKeeper (напрямую или в nested классе), так что для расстрельной ситуации придется постараться.
public void DoSomething(Example example) { this.JustInt = example.JustInt; // Вполне валидная строка, некоторых удивляет }
Наверное, такое может удивить только программистов, не представляющих, что такое копирующий конструктор.
Для красоты рефлексию можно завернуть в DynamicObject
:
List<int> realList = new List<int>();
dynamic exposedList = ExposedObject.From(realList);
// Read a private field - prints 0
Console.WriteLine(exposedList._size);
Подробности и ссылка на библиотеку.
Таким же образом можно завернуть и вариант с expression trees.
А можно вопрос? Для чего всё это? Скрытые поля ведь не просто так сделаны скрытыми. Если б разработчик хотел, чтоб к полю был доступ он бы сделал это либо через публичное свойство, или (если он старовер) через публичные get()-set() функции.
Я вижу 2 варианта:
1) Желание прострелить себе ногу модифицируя осознано скрытые разработчиком поля объектов, т.е. явно нарушить архитектуру приложения;
2) Изобрести костыль к кривому приложению, который, опять-же может оказаться выстрелом в ногу и сделать приложение ещё кривее.
Я вижу 2 варианта:
1) Желание прострелить себе ногу модифицируя осознано скрытые разработчиком поля объектов, т.е. явно нарушить архитектуру приложения;
2) Изобрести костыль к кривому приложению, который, опять-же может оказаться выстрелом в ногу и сделать приложение ещё кривее.
Последняя задача — кастомный сериализатор, который работает со скрытыми полями. В принципе, можно было обойти ту проблему иначе, но за счет пары дополнительных факторов было решено пилить свой сериализатор, в том числе с доступом к приватным полям.
По вашей градации — пункт 2. Разве что, багов после «костыля» стало меньше, и ноги пока целы.
По вашей градации — пункт 2. Разве что, багов после «костыля» стало меньше, и ноги пока целы.
Промах
Sign up to leave a comment.
Четыре способа извлечения значений из скрытых полей в C#