touint sbyte que int16 ejemplo c#

sbyte - signed byte c#



Use byte[] como clave en el diccionario (7)

Necesito usar un byte[] como clave en un Dictionary . Como byte[] no anula el método predeterminado GetHashCode , dos objetos byte[] separados que contienen los mismos datos usarán dos ranuras separadas en el diccionario. Básicamente lo que quiero es esto:

Dictionary<byte[], string> dict = new Dictionary<byte[], string>(); dict[new byte[] {1,2,3}] = "my string"; string str = dict[new byte[] {1,2,3}]; // I''d like str to be set to "my string" at this point

¿Hay una manera simple de hacer esto? Lo único que se me ocurre es crear una clase contenedora que solo contenga un byte[] y anular GetHashCode función del contenido del byte[] , pero esto parece propenso a errores.


¿Podrías convertir el byte [] a una cadena y usar eso como la clave?

Algo como:

ASCIIEncoding enc = new ASCIIEncoding(); byte[] input; string demo = new string(enc.GetChars(input)); byte[] decode = enc.GetBytes(demo.ToCharArray());


Acabo de hacer EqualityComparer un poco más genérico, al no trabajar en matrices, pero en IEnumerable<T> .

Debido al hecho de que ahora tenemos una T , necesitamos poder especificar un comparador de igualdad opcional para los elementos.

Por último, GetHashCode() no debe lanzarse nunca y, a veces, lo necesita rápido y, a veces, lo necesita con más precisión en la primera ejecución. Por lo tanto, puede definir opcionalmente una precisión de cuántos elementos (máximo) debe tenerse en cuenta el código hash para nuestro propio hash.

public class EnumerableEqualityComparer<T> : IEqualityComparer<IEnumerable<T>> { private static readonly Lazy<IEqualityComparer<IEnumerable<T>>> Lazy = new Lazy<IEqualityComparer<IEnumerable<T>>>(() => new EnumerableEqualityComparer<T>()); private int accuracy; private IEqualityComparer<T> comparer; public EnumerableEqualityComparer() : this(-1) { } public EnumerableEqualityComparer(int accuracy) : this(accuracy, null) { } public EnumerableEqualityComparer(IEqualityComparer<T> elementEqualityComparer) : this(-1, elementEqualityComparer) { } public EnumerableEqualityComparer(int accuracy, IEqualityComparer<T> elementEqualityComparer) { if (accuracy < 0) { accuracy = 4; } this.accuracy = accuracy; comparer = elementEqualityComparer ?? EqualityComparer<T>.Default; } public static IEqualityComparer<IEnumerable<T>> Default { get; private set; } = Lazy.Value; public bool Equals(IEnumerable<T> x, IEnumerable<T> y) { if (ReferenceEquals(x, y)) { return true; } if (ReferenceEquals(x, null) || ReferenceEquals(y, null)) { return false; } return x.SequenceEqual(y, comparer); } public int GetHashCode(IEnumerable<T> obj) { if (ReferenceEquals(obj, null)) { return -1; } var count = (obj as ICollection<T>)?.Count ?? 1; var hashCode = count * 49297; foreach (var item in obj.Take(accuracy)) { hashCode += comparer.GetHashCode(item) * 17123; } return hashCode; } }


Cuando recupera los elementos del diccionario, está utilizando un nuevo operador para el byte []. Esto buscará una instancia diferente (nueva) de byte [] en el diccionario que no está presente.

Aquí hay una solución que funcionará:

var dict = new Dictionary<byte[], string>(); var b = new byte[] { 1,2,3}; dict[b] = "my string"; var value = dict[b]; Console.WriteLine(value);


Entonces, la respuesta de JaredPar no es mala, pero podría ser mejor en algunos aspectos. En primer lugar, la página de IEqualityComparer dice "Recomendamos que se deriva de la clase EqualityComparer en lugar de implementar la interfaz IEqualityComparer".

En segundo lugar, se supone que la implementación de GetHashCode es rápida . Se usa para eliminar rápidamente objetos obviamente diferentes, que obviamente sería una pérdida de tiempo ejecutar Equals. Así que GetHashCode debería ser mucho más rápido que ejecutar Equals.

En tercer lugar, devolver la suma de la matriz de bytes como lo hizo JaredPar, es muy probable que produzca colisiones, si los bytes están en orden diferente, o las diferencias relativas se cancelan entre sí, etc.

Entonces, recomendaría una solución como esta:

public class ByteArrayComparer : EqualityComparer<byte[]> { public override bool Equals(byte[] first, byte[] second) { if (first == null || second == null) { // null == null returns true. // non-null == null returns false. return first == second; } if (ReferenceEquals(first, second)) { return true; } if (first.Length != second.Length) { return false; } // Linq extension method is based on IEnumerable, must evaluate every item. return first.SequenceEqual(second); } public override int GetHashCode(byte[] obj) { if (obj == null) { throw new ArgumentNullException("obj"); } // quick and dirty, instantly identifies obviously different // arrays as being different return obj.Length; } }

Arriba, volviendo obj.Length, es realmente rápido y sucio, pero también propenso a devolver muchas colisiones. Pienso que podemos hacerlo mejor.

Si vas a examinar todos los bytes, algo como esto es menos propenso a colisiones que la simple suma de bytes como en la respuesta de JaredPar. Pero, de nuevo, esto examina todos los elementos, por lo que no funcionará mejor que ejecutar Equals. También podría devolver 0 incondicionalmente, y siempre forzar el uso de Iguales.

Enfatizo: esto es mejor que devolver la suma como en la respuesta de JaredPar. Y siempre devolviendo 0 es mejor que esto. Y devolver obj.Length es mejor que devolver 0.

// This is not recommended. Performance is too horrible. public override int GetHashCode(byte[] obj) { // Inspired by fletcher checksum. Not fletcher. if (obj == null) { throw new ArgumentNullException("obj"); } int sum = 0; int sumOfSum = 0; foreach (var val in obj) { sum += val; // by default, addition is unchecked. does not throw OverflowException. sumOfSum += sum; } return sum ^ sumOfSum; }

Si usted sabe que las matrices de bytes [] que está utilizando como la clave eran hashes criptográficos, entonces puede utilizar esta suposición para su beneficio, y simplemente devolver los primeros 4 bytes convertidos a int . Probablemente también funciona bien, para matrices de bytes de propósito general:

// This implementation works great if you assume the byte[] arrays // are themselves cryptographic hashes. It probably works alright too, // for general-purpose byte arrays. public override int GetHashCode(byte[] obj) { if (obj == null) { throw new ArgumentNullException("obj"); } if (obj.Length >= 4) { return BitConverter.ToInt32(obj, 0); } // Length occupies at most 2 bits. Might as well store them in the high order byte int value = obj.Length; foreach (var b in obj) { value <<= 8; value += b; } return value; }


Por defecto, byte[] se comparará por referencia, que no es lo que quiere en este caso. Lo que debe hacer es especificar un IEqualityComparer<byte[]> y hacer la comparación que desee.

Por ejemplo

public class ByteArrayComparer : IEqualityComparer<byte[]> { public bool Equals(byte[] left, byte[] right) { if ( left == null || right == null ) { return left == right; } return left.SequenceEqual(right); } public int GetHashCode(byte[] key) { if (key == null) throw new ArgumentNullException("key"); return key.Sum(b => b); } }

Entonces puedes hacer

var dict = new Dictionary<byte[], string>(new ByteArrayComparer());

Solución para 2.0

public class ByteArrayComparer : IEqualityComparer<byte[]> { public bool Equals(byte[] left, byte[] right) { if ( left == null || right == null ) { return left == right; } if ( left.Length != right.Length ) { return false; } for ( int i= 0; i < left.Length; i++) { if ( left[i] != right[i] ) { return false; } } return true; } public int GetHashCode(byte[] key) { if (key == null) throw new ArgumentNullException("key"); int sum = 0; foreach ( byte cur in key ) { sum += cur; } return sum; } }


Tu pensamiento fue mi primer pensamiento también. No creo que sea propenso a errores. Pero si no te gusta esa opción, puedes crear una clase que implemente IEqualityComparer y pasarle una instancia al constructor del diccionario.


using System; using System.Collections; using System.Collections.Generic; [Serializable] class StructuralEqualityComparer : IEqualityComparer, IEqualityComparer<object> { public new bool Equals(object x, object y) { var s = x as IStructuralEquatable; return s == null ? object.Equals(x, y) : s.Equals(y, this); } public int GetHashCode(object obj) { var s = obj as IStructuralEquatable; return s == null ? EqualityComparer<object>.Default.GetHashCode(obj) : s.GetHashCode(this); } }