c# - example - ¿Por qué no puedo comparar un KeyValuePair<TKey, TValue> con el valor predeterminado?
foreach key value c# (6)
(Si no te importa la discusión sobre genéricos vinculada a este error, puedes saltar al final para obtener tu respuesta "real")
Como dice el error, no hay pruebas de igualdad para KeyValuePairs (es decir, no hay un método de comparación incorporado). La razón para esto es evitar tener que colocar restricciones en los tipos de KeyValuePairs (hay muchos casos en los que las comparaciones de clave y valor nunca se realizarían).
Obviamente, si desea comparar los KeyValuePairs, me imagino que lo que desea es verificar si las claves y los valores son iguales. Pero esto implica un lío completo de cosas, en particular que TKey y TValue son ambos tipos comparables (es decir, implementan la interfaz IComparable)
Puede escribir su propia función de comparación entre pares de valores clave, por ejemplo:
static bool KeyValueEqual<TKey , TValue>(KeyValuePair<TKey, TValue> fst,
KeyValuePair<TKey, TValue> snd)
where TValue:IComparable
where TKey:IComparable
{
return (fst.Value.CompareTo(snd.Value)==0)
&& (snd.Key.CompareTo(fst.Key)==0);
}
(Disculpe la sangría terrible)
Aquí imponemos que TKey y TValue son comparables (a través de la función de miembro CompareTo).
La función CompareTo (tal como se define para los tipos predefinidos) devuelve 0 cuando dos objetos son iguales, à la strcmp. a.ComparesTo (b) == 0 significa que a y b son el "mismo" (en valor, no el mismo objeto).
entonces esta función tomaría dos KVPs (k, v) y (k '', v'') y devolvería verdadero si y solo si k == k ''y v == v'' (en el sentido intuitivo).
Pero, ¿es esto necesario? Parece que su prueba en la que tiene problemas se basa en algún tipo de verificación a la vuelta de FirstOrDefault.
Pero hay una razón por la que su función se llama FirstOrDefault :
Devuelve el primer elemento de la secuencia que satisface una condición o un valor predeterminado si no se encuentra dicho elemento.
(énfasis mío)
Esta función devuelve valores predeterminados si no se encuentra algo , lo que significa que si no se verifica su predicado, obtendrá un KeyValuePair igual a (predeterminado (TKey), por defecto (TValue).
Por lo tanto, su código (tiene la intención) de verificar si pair.Key == default (TKey), solo para devolver el valor predeterminado (TKey) de todos modos . ¿No tendría más sentido devolver el par. Clave desde el principio?
En .Net 2.5 generalmente puedo obtener una comparación de igualdad (==) entre un valor y su tipo predeterminado
if (myString == default(string))
Sin embargo, recibo la siguiente excepción cuando intento ejecutar una comparación de igualdad en un KeyValuePair predeterminado y un KeyValuePair
Ejemplo de código (a partir de un método de preextensión, clase ListUtilities estática proto-lambda :))
public static TKey
FirstKeyOrDefault<TKey, TValue>(Dictionary<TKey, TValue> lookups,
Predicate<KeyValuePair<TKey, TValue>> predicate)
{
KeyValuePair<TKey, TValue> pair = FirstOrDefault(lookups, predicate);
return pair == default(KeyValuePair<TKey, TValue>) ?
default(TKey) : pair.Key;
}
Excepción:
El operador ''=='' no se puede aplicar a los operandos del tipo ''System.Collections.Generic.KeyValuePair <string, object>'' y ''System.Collections.Generic.KeyValuePair <string, object>''
¿Es porque, como una estructura, KeyValuePair no se puede anular? Si este es el caso, ¿por qué, como presumiblemente, se implementó el valor predeterminado para manejar tipos no anulables?
EDITAR
Para el registro, elegí a @Chris Hannon como respuesta seleccionada, ya que me dio lo que estaba buscando, la opción más elegante y una explicación sucinta, sin embargo, animo a leer @Dasuraga para una explicación muy completa de por qué esto es el caso
Esto sucede porque KeyValuePair<TKey, TValue>
no define un operador == personalizado y no está incluido en la lista predefinida de tipos de valores que pueden usarlo.
Aquí hay un enlace a la documentación de MSDN para ese operador.
Para tipos de valores predefinidos, el operador de igualdad (==) devuelve verdadero si los valores de sus operandos son iguales, de lo contrario es falso.
Su mejor apuesta para una comprobación de igualdad en este caso, porque esta no es una estructura sobre la que tiene control, es llamar a default(KeyValuePair<TKey,TValue>).Equals(pair)
lugar.
Esto va en una dirección ligeramente diferente, pero supongo que consultó un Diccionario para obtener este resultado, y luego desea verificar si arrojó un resultado válido o no.
Encontré que el mejor método para hacer esto era consultar el valor real en lugar de todo el KeyValuePair, como este:
var valitem = MyDict.Values.FirstOrDefault (x => x.Something == aVar);
Ahora puede verificar si valitem es nulo o no. Una vez más, no responde directamente su pregunta, pero ofrece lo que podría ser un enfoque alternativo para su objetivo previsto.
Los valores predeterminados se basan en tipos escalares.
Hágase esta pregunta: ¿Qué significa que KVP tenga un valor predeterminado?
Para los no escalares, el valor predeterminado es lo que obtenga al llamar al constructor nil. Suponiendo que KVP Equals realiza una comparación de identidad de instancia, esperaría que devuelva falso ya que obtiene un nuevo objeto cada vez que se invoca el constructor.
No funciona por la misma razón que la siguiente:
var kvp = new KeyValuePair<string,string>("a","b");
var res = kvp == kvp;
La pista está en el mensaje de error, naturalmente. (No tiene nada que ver con el default
).
Operator ''=='' cannot be applied to operands of type ''System.Collections.Generic.KeyValuePair<string,string>'' and ''System.Collections.Generic.KeyValuePair<string,string>''
El operador ==
no está definido para KeyValuePair<T,U>
.
Mensajes de error FTW.
Feliz codificación.
Para poder utilizar el operador de igualdad "==" en cualquier clase o estructura, debe anular el operador: http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx
KeyValuePair no lo hace, y por lo tanto obtienes el error de compilación. Tenga en cuenta que obtendrá el mismo error si prueba esto:
var k1 = new KeyValuePair<int,string>();
var k2 = new KeyValuePair<int,string>();
bool b = k1 == k2; //compile error
EDITAR: Como Eric Lippert me corrigió en los comentarios, las clases obviamente no necesitan anular el operador de igualdad para que "==" sea válido. Compilará bien y hará un control de igualdad de referencia. Mi error.