2011-03-27 12 views
6

Quiero hacer que el int en IDictionary<int, Driver> sea un poco menos oscuro acerca de su significado, así que pensé que tal vez sería una buena idea encintarlo. El resultado sería algo así como IDictionary<finishPosition, Driver>.¿Es posible envolver un entero y llamarlo como un entero?

Preferiblemente, finishPosition debe poderse asignar como este finishPosition = 1.

No sé si esto es posible y cómo.

Respuesta

5

Puede usar struct con una conversión implícita.

public struct FinishPosition { 
    public readonly int Position; 

    public FinishPosition(int position) { 
     this.Position = position; 
    } 

    public static implicit operator FinishPosition(int position) { 
     return new FinishPosition(position); 
    } 
} 


// ... 

Dictionary<FinishPosition, Driver> dict = new Dictionary<FinishPosition, Driver>(); 
Driver bob = new Driver(); 

// The following two lines are effectively equivalent 
dict[new FinishPosition(7)] = bob; 
dict[7] = bob; 

// So are these two 
bob = dict[7]; 
bob = dict[new FinishPosition(7)] 
+0

Esta es claramente una mejor solución que la mía. –

+0

Parece correcto y lo que se preguntó, pero es un poco sobrecargado ... Y para la legibilidad (y la seguridad) omitiría la conversión implícita. –

+0

@Henk: El punto entero de esto es la conversión implícita; 'Dañe la legibilidad tanto como pensaría cuando solo funciona de una manera. – configurator

1

Se podría utilizar una enumeración:

enum Position { Finish, Some, Other } 

IDictionary<Position, Driver> lookup = ...; 

Driver d = lookup[Position.Finish]; 
+0

Tal vez entiendo que mal (o al revés) - Pero el finishPosition debe ser asignable con diferentes tipos de enteros, como finishPosition = 1, finishPosition = 2, finishPosition = 3, y asigne a cada uno de ellos un objeto Driver para esa posición, y almacénelos en el diccionario. el diccionario serán los controladores y las posiciones en que terminaron. –

+0

Lo mejor es nombrar esos enteros (Algunos, Otros) pero también puede asignar un valor int arbitrario. Sin embargo, tal vez me equivoqué de nombre, adaptarse. –

+0

No puede asignar enteros arbitrarios a una variable enum. Solo '0' o un valor' enum', o con conversión explícita. – configurator

5

Por supuesto, sólo tiene que utilizar esta directiva using:

using FinishPosition = System.Int32;

en la parte superior de su archivo fuente, y escribir el código del mismo modo que tiene en tu ejemplo.

Si usa la directiva using de esta manera, FinishPosition es un int y otros archivos lo verán como un int - no hay un nuevo tipo definido FinishPosition (gracias por el configurador en los comentarios).

+0

¡Impresionante! ¿Sabes si hay un equivalente en VB.NET para este truco? –

+0

Acabo de probarlo y funciona en VB.NET también. Imports myValue = System.Int32 –

+0

Esto parece un truco de C loco. +1 –

1

En mi opinión, es bueno utilizar AbstractDataType patrón en cualquier lugar en donde se utiliza un valor general, con intenciones específicas (este caso se ha hecho por muchos otros con ejemplos como porcentaje, ReadonlyString, ConnectionString, etc.)

Nota: Personalmente, creo que tener conversiones implícitas desde y hacia ellos hace que todo termine (al tener una conversión implícita, ya no hay garantía del compilador de que los valores genéricos se usen con intención específica en el lugar correcto) .

Aquí hay una muestra que debería inspirarlo para que lo haga a su manera: aún puede elegir el nivel de conveniencia/verbosidad que prefiera.Se muestran dos enfoques:

  • índices _byInt un diccionario por PseudoInt
  • índices _byEnum un diccionario mediante una enumeración: tipo int

Notas

  • si se quiere #define IMPLICIT_CONVERSIONS obtener conversiones implícitas al tipo de índice base (por lo que a int o a la enumeración)
  • este extrapola a todos los tipos de valores, incluidos los definidos por el usuario (probarlo con su estructura XYZCoord :))
  • echar un vistazo overhere if you really wanted conversions to and from Enum types

Sin más preámbulos:

#define IMPLICIT_CONVERSIONS 
using System.Collections.Generic; 

namespace NS 
{ 
    public enum PositionEnum : int { Begin = 0, Normal = 1, End = 99 } 

    public struct Pseudo<T> where T : struct 
    { 
     public T Value; 
     public Pseudo(T value) { Value = value; } 
#if IMPLICIT_CONVERSIONS 
     public static implicit operator T(Pseudo<T> pi) { return pi.Value; } 
     public static implicit operator Pseudo<T>(T ni) { return new Pseudo<T>(ni); } 
#endif 
    } 

    static class Program 
    { 
     private static Pseudo<T> AsPseudo<T>(this T value) where T : struct 
     { 
      return new Pseudo<T>(value); 
     } 

     private static readonly IDictionary<Pseudo<int>, string> _byInt = 
      new Dictionary<Pseudo<int>, string>() 
       { { 0, "aap" }, 
        { 1, "noot" }, 
        { 99, "mies" }, 
       }; 

     private static readonly IDictionary<Pseudo<PositionEnum>, string> _byEnum = 
      new Dictionary<Pseudo<PositionEnum>, string>() 
       { { PositionEnum.Begin, "aap" }, 
        { PositionEnum.Normal, "noot" }, 
        { PositionEnum.End, "mies" }, 
       }; 

     public static void Main(string[] args) 
     { 
      string s; 
      s = _byInt[0]; 
      s = _byEnum[PositionEnum.Normal]; 
     } 
    } 
} 
+0

¡Gracias por su respuesta! –

0

acabo adaptado el RichEnum generic baseclass en la pregunta que vinculé antes [1]

Yo diría que prefiero este método porque realmente me parece el más flexible a largo plazo. El único inconveniente que se me ocurre, realmente, es que el tipo de RichEnum ya no puede ser un tipo de valor.

cabeza para ver lo que quiero decir (incluye una muestra totalmente a correr de nuevo):

[1] Can we define implicit conversions of enums in c#?