una son sirve que publicas privado privadas privada para otra modificadores modificador metodo los desde cuales como clase acceso acceder c# arrays generics struct equals

c# - son - T[]. Contiene una estructura y clase que se comporta de manera diferente



para que sirve private en c# (3)

Creo que es porque ambos usan su propia implementación base de Equals

Las clases heredan Object.Equals que implementa la igualdad de identidad, Structs hereda ValueType.Equals que implementa igualdad de valor.

Esta es una pregunta de seguimiento a esto: Lista <T> .Contains y T []. Contiene comportamientos diferentes

T[].Contains se comporta de manera diferente cuando T es clase y struct. Supongamos que tengo esta estructura :

public struct Animal : IEquatable<Animal> { public string Name { get; set; } public bool Equals(Animal other) //<- he is the man { return Name == other.Name; } public override bool Equals(object obj) { return Equals((Animal)obj); } public override int GetHashCode() { return Name == null ? 0 : Name.GetHashCode(); } } var animals = new[] { new Animal { Name = "Fred" } }; animals.Contains(new Animal { Name = "Fred" }); // calls Equals(Animal)

Aquí, Equals genérico se llama correctamente como esperaba.

Pero en caso de una clase :

public class Animal : IEquatable<Animal> { public string Name { get; set; } public bool Equals(Animal other) { return Name == other.Name; } public override bool Equals(object obj) //<- he is the man { return Equals((Animal)obj); } public override int GetHashCode() { return Name == null ? 0 : Name.GetHashCode(); } } var animals = new[] { new Animal { Name = "Fred" } }; animals.Contains(new Animal { Name = "Fred" }); // calls Equals(object)

Se llama a Equals no genérico , quitando el beneficio de implementar `IEquatable.

¿Por qué las llamadas de matriz son diferentes para struct[] y class[] , a pesar de que ambas colecciones parecen genéricas ?

La rareza de la matriz es tan frustrante que estoy pensando en evitarla por completo ...

Nota: La versión genérica de Equals se llama solo cuando la estructura implementa IEquatable<T> . Si el tipo no implementa IEquatable<T> , se llama a la sobrecarga no genérica de Equals independientemente de si es class o struct .


Parece que en realidad no es Array.IndexOf () el que termina siendo llamado. Al ver la fuente de eso, hubiera esperado que se llamara a Equals (objeto) en ambos casos si ese fuera el caso. Al observar el seguimiento de la pila en el punto donde se llama a Equals, deja más claro por qué obtiene el comportamiento que está viendo (el tipo de valor obtiene Igual (Animal), pero el tipo de referencia obtiene Igual (objeto).

Aquí está el seguimiento de la pila para el tipo de valor (struct Animal)

at Animal.Equals(Animal other) at System.Collections.Generic.GenericEqualityComparer`1.IndexOf(T[] array, T value, Int32 startIndex, Int32 count) at System.Array.IndexOf[T](T[] array, T value, Int32 startIndex, Int32 count) at System.Array.IndexOf[T](T[] array, T value) at System.SZArrayHelper.Contains[T](T value) at System.Linq.Enumerable.Contains[TSource](IEnumerable`1 source, TSource value)

Aquí está el seguimiento de la pila para el tipo de referencia (objeto Animal)

at Animal.Equals(Object obj) at System.Collections.Generic.ObjectEqualityComparer`1.IndexOf(T[] array, T value, Int32 startIndex, Int32 count) at System.Array.IndexOf[T](T[] array, T value, Int32 startIndex, Int32 count) at System.Array.IndexOf[T](T[] array, T value) at System.SZArrayHelper.Contains[T](T value) at System.Linq.Enumerable.Contains[TSource](IEnumerable`1 source, TSource value)

A partir de esto, puede ver que no es Array.IndexOf que se está llamando - es Array.IndexOf [T]. Ese método termina usando comparadores de Igualdad. En el caso del tipo de referencia, usa ObjectEqualityComparer que llama Igual (objeto). En el caso del tipo de valor, usa GenericEqualityComparer que llama Igual (Animal), presumiblemente para evitar un boxeo caro.

Si observa el código fuente de IEnumerable en http://www.dotnetframework.org , tiene este bit interesante en la parte superior:

// Note that T[] : IList<t>, and we want to ensure that if you use // IList<yourvaluetype>, we ensure a YourValueType[] can be used // without jitting. Hence the TypeDependencyAttribute on SZArrayHelper. // This is a special hack internally though - see VM/compile.cpp. // The same attribute is on IList<t> and ICollection<t>. [TypeDependencyAttribute("System.SZArrayHelper")]

No estoy familiarizado con TypeDependencyAttribute, pero a partir del comentario, me pregunto si hay algo de magia que sea especial para Array. Esto puede explicar cómo IndexOf [T] termina siendo llamado en lugar de IndexOf a través de IList.Contains de Array.


El objetivo principal de IEquatable<T> es permitir comparaciones de igualdad razonablemente eficientes con tipos de estructura genéricos. Se pretende que IEquatable<T>.Equals((T)x) se comporte exactamente igual que Equals((object)(T)x); excepto que si T es un tipo de valor, el primero evitará una asignación de montón que será necesaria para este último. Aunque IEquatable<T> no obliga a T a ser un tipo de estructura, y las clases selladas pueden en algunos casos recibir un leve beneficio de rendimiento al usarlo, los tipos de clase no pueden recibir casi tanto beneficio de esa interfaz como lo hacen los tipos de estructura. Una clase escrita correctamente puede funcionar un poco más rápido si el código externo usa IEquatable<T>.Equals(T) lugar de Equals(Object) , pero de lo contrario no debería importar qué método de comparación se usa. Debido a que la ventaja de rendimiento de usar IEquatable<T> con las clases nunca es muy grande, el código que sabe que está usando un tipo de clase podría decidir que el tiempo requerido para verificar si el tipo pasa a implementar IEquatable<T> probablemente no se recuperaría la ganancia de rendimiento que la interfaz podría ofrecer de manera plausible.

A propósito, vale la pena señalar que si X e Y son clases "normales", X.Equals (Y) puede ser legítimamente verdadero si X o Y deriva del otro. Además, una variable de un tipo de clase no sellada puede compararse legítimamente igual a uno de cualquier tipo de interfaz, ya sea que la clase implemente o no esa interfaz. En comparación, una estructura solo se puede comparar con una variable de su propio tipo, Object , ValueType o una interfaz que la estructura misma implementa. El hecho de que las instancias de tipo de clase puedan ser "iguales" a un rango mucho más amplio de tipos de variables significa que el IEquatable<T> no es tan aplicable con ellos como con los tipos de estructura.

PD: hay otra razón por la que las matrices son especiales: admiten un estilo de covarianza que las clases no pueden. Dado

Dog Fido = new Dog(); Cat Felix = new Cat(); Animal[] meows = new Cat[]{Felix};

es perfectamente legal probar meows.Contains(Fido) . Si los meows fueron reemplazados por una instancia de Animal[] o Dog[] , la nueva matriz podría contener Fido ; incluso si no fuera así, uno podría legítimamente tener una variable de algún tipo desconocido de Animal y querer saber si está contenido dentro de los meows . Incluso si Cat implementa IEquatable<Cat> , tratando de usar el IEquatable<Cat>.Equals(Cat) para probar si un elemento de meows es igual a Fido , fallaría porque Fido no se puede convertir en un Cat . Puede haber formas para que el sistema use IEquatable<Cat> cuando es viable y Equals(Object) cuando no lo es, pero agregaría mucha complejidad, y sería difícil hacerlo sin un costo de rendimiento que excedería el de simplemente usar Equals(Object) .