Представьте себе следующий класс, используемый в качестве объекта параметров для некоторого сложного запроса.Использование изменяемого объекта в качестве хеш-ключа
public class RequestParameters
{
///<summary>Detailed User-Friendly Descriptions.</summary>
string Param1 { get; set; } = "Default";
int? Param2 { get; set; }
bool Param3 { get; set; } = true;
...
string ParamN { get; set; }
}
Я хочу, чтобы пользователи могли создавать и настраивать эти параметры объекта, как они считают нужным, прежде чем передать его для использования в запросе:
RequestParameters _filtered = new RequestParameters();
filtered.Param1 = "yellow";
filtered.Param3 = true;
_someInstance.InvokeRequest(_filtered);
Когда я обработки запроса, я хотите кэшировать результат на основе предоставленных параметров запроса. Было бы тривиально реализовать некоторый метод клонирования и IEquatable<RequestParameters>
, и переопределить Equals()
и GetHashCode()
по вышеуказанному классу RequestParameters
, но последнее считается широко распространенным методом - RequestParameters
является изменяемым, и если экземпляр был изменен после вставки, он может испортиться мой кеш.
С другой стороны, я чувствую, что это было бы огромным количеством дублирования кода (и головной боли обслуживания), если бы я должен был выполнить какую-то копию этого класса ReadOnlyRequestParameters
, только без сеттеров.
Неужели было бы так плохо использовать этот класс в качестве ключа кэш-памяти, если я стараюсь делать копии экземпляров, которые пользователи отправляют, и никогда не изменять их после вставки в кеш? Какие альтернативы вы бы предложили, если бы вы были разработчиком, работающим с одними и теми же объектами?
Как насчет какого-то завода, где вы собираете все параметры, возможно, меняя их по пути и возвращение неотменяемая копия их по требованию? Что касается «дублирования кода» и «головной боли обслуживания»: как насчет использования T4 для сохранения свойств чтения/записи фабрики и свойств readonly неизменяемой копии в синхронизации? – Corak
У вас есть три варианта. (1) летать на сиденье ваших штанов и просто использовать объект как есть, и надеяться, что никто не мутирует его. (2) Внедрите метод '.Freeze()', который предотвращает дальнейшие изменения объекта, чтобы вы могли положиться на 'GetHashCode' /' Equals'. (3) Создайте версию вашего класса только для чтения. – Enigmativity
Еще одна проблема с внедрением GetHashCode() над изменяемыми полями - это часть открытого интерфейса (общедоступного) класса. Клиенты могут захотеть хранить экземпляры в своих собственных словарях или наборах HashSets, и они могут ожидать поведения эталонного равенства, учитывая, что класс изменен. – Blorgbeard