Cualquier colección interna débil (para objetos inmutables)

En algunas situaciones que involucran objetos inmutables, será posible que surjan muchos objetos distintos que son semánticamente idénticos. Un ejemplo simple sería leer muchas líneas de texto de un archivo en cadenas. Desde la perspectiva del programa, el hecho de que dos líneas tengan la misma secuencia de caracteres sería "coincidencia", pero desde la perspectiva del programador puede esperarse una gran cantidad de duplicación. Si muchas instancias de cadenas son idénticas, cambiar las referencias a esas distintas instancias en referencias a una sola instancia ahorrará memoria y también facilitará las comparaciones entre ellas (si dos referencias de cadenas apuntan a la misma cadena, no es necesario hacer un carácter) comparación de caracteres para determinar que son idénticos).

Para algunos escenarios, el servicio de internado de cadenas provisto por el sistema puede ser útil. Tiene, sin embargo, un par de severas limitaciones:

Una vez que se ha internado una cadena, esa copia internada vivirá para siempre, exista o no alguna otra referencia a ellaEl servicio de internado de cadenas solo funciona con cadenas y no se puede utilizar con ningún otro tipo inmutable.

Si existiera un verdaderoWeakDictionary<ImmutableClassType, ImmutableClassType> (para cada elemento, la clave y el valor serían idénticos), el código podría hacer algo como:

if (theDict.TryGetValue(myString, ref internedString))
  myString = internedString;
else
  theDict[myString] = myString;

Desafortunadamente, no tengo conocimiento de ningún incorporadoWeakDictionary<keyType, valType> clase en .net. Además, parecería inútil generar una referencia débil para la clave y el valor de cada elemento, cuando ambas referencias siempre apuntan a lo mismo.

He leído algo sobreConditionalWeakTable, y eso suena como una clase interesante, pero no creo que sea utilizable aquí, ya que el objetivo es poder tomar una instancia y encontrar otra instancia independiente que sea semánticamente equivalente.

Para situaciones en las que las instancias de una clase tendrán una vida útil bien definida, puede ser razonable usar unDictionary para fusionar instancias idénticas. En muchos casos, sin embargo, puede ser difícil saber cuándo unDictionary Deben ser abandonados o los artículos dentro de ella limpiados. UNAWeakReferenceLa colección de interning basada en la base evitaría tales problemas. ¿Existe tal cosa, o podría ser implementada fácilmente?

Apéndice Como señaló svick, unDictionary<WeakReference, WeakReference> sería algo problemático ya que no habría una forma práctica de definir unIEqualityComparer que tendría una vidaWeakReference devuelve elGetHashCode valor de su objetivo, y tener un muerto continuar para devolver ese valor. Uno podría definir una estructura que contendría un valor de código hash de destino entero (establecido en el constructor), y cuyo propioGetHashCode devolvería ese número entero. Una ligera mejora podría ser utilizar unConditionalWeakTable para vincular el objetivo de laWeakReference a un objeto finalizable que podría usarse para poner en cola los elementos de la tabla para su eliminación.

No estoy seguro de cuál es el equilibrio adecuado entre tratar de limpiar con entusiasmo el diccionario, en lugar de adoptar un enfoque más pasivo (por ejemplo, realizar un barrido al agregar un elemento si ha habido al menos un GC desde el último barrido y el número de los elementos agregados desde que el último barrido supera el número de elementos que lo sobrevivieron). Barrer a través de todo en el diccionario no va a ser gratuito, pero ConditionalWeakTable probablemente tampoco va a ser gratis.

PPS Otra idea en la que estaba pensando, pero pensé que probablemente no sería tan útil como un enfoque de internamiento débil, sería tener un tipo lógicamente inmutable con un valor de "marca de tiempo" mutable, y tener un método de comparación que acepte su argumentos porref. Si se encuentra que dos instancias diferentes son iguales, se examinarán sus valores de marca de tiempo. Si ambos son cero, se les asignarán números negativos consecutivos de un contador global (-1, -2, -3, etc.). El parámetro que tenía (o fue asignado) el valor de marca de tiempo más bajo sería reemplazado por el otro.

Usando tal enfoque, si muchas instancias de objetos se compararan repetidamente unas con otras, muchas de las referencias serían reemplazadas con referencias a instancias "más antiguas". Dependiendo de los patrones de uso, esto puede hacer que la mayoría de las instancias de objetos idénticos se fusionen sin el uso de ningún tipo de diccionario de internado. Sin embargo, aplicar un enfoque de este tipo con objetos anidados requeriría que los objetos "inmutables" permitan que las referencias de objetos anidados se muten para apuntar a otros objetos anidados supuestamente idénticos. Esto debería estar bien si los objetos "supuestamente idénticos" siempre lo son, pero podría causar un mal comportamiento bastante extraño si no lo fuera.

Respuestas a la pregunta(1)

Su respuesta a la pregunta