Tengo una clase como la siguiente:

public class DropDownControl<T, Key, Value> : BaseControl
    where Key: IComparable
{
    private IEnumerable<T> mEnumerator;
    private Func<T, Key> mGetKey;
    private Func<T, Value> mGetValue;
    private Func<Key, bool> mIsKeyInCollection;

    public DropDownControl(string name, IEnumerable<T> enumerator, Func<T, Key> getKey, Func<T, Value> getValue, Func<Key, bool> isKeyInCollection)
        : base(name)
    {
        mEnumerator = enumerator;
        mGetKey = getKey;
        mGetValue = getValue;

        mIsKeyInCollection = isKeyInCollection;
    }

Y quiero agregar una función de conveniencia para los Diccionarios (debido a que el apoyo de todas las operaciones de manera eficiente en sus propios).

Pero el problema es que un constructor sería sólo especificar una Clave y un Valor, pero no T directamente, pero es sólo KeyValuePair. Es allí una manera de decirle al compilador para este constructor T es KeyValuePair, como:

public DropDownControl<KeyValuePair<Key, Value>>(string name, IDictionary<Key, Value> dict) { ... }

Actualmente yo uso una estática Crear una función como la solución, pero me gustaría directa constructor mejor.

public static DropDownControl<KeyValuePair<DKey, DValue>, DKey, DValue> Create<DKey, DValue>(string name, IDictionary<DKey, DValue> dictionary)
            where DKey: IComparable
        {
            return new DropDownControl<KeyValuePair<DKey, DValue>, DKey, DValue>(name, dictionary, kvp => kvp.Key, kvp => kvp.Value, key => dictionary.ContainsKey(key));
        }

OriginalEl autor Fionn | 2008-10-04

2 Comentarios

  1. 12

    No, básicamente. El método estático en una no-clase genérica (como DropDownControl [no <>]) es el mejor enfoque, como usted debe ser capaz de utilizar la inferencia de tipo cuando se llama Create() – es decir,

    var control = DropDownControl.Create(name, dictionary);

    C# 3.0 ayuda aquí, tanto a través de «var» (muy bienvenidos aquí) y por la muy mejorada de tipo genérico reglas de inferencia. En algunos (más general), otra opción similar es un método de extensión, sino un método de extensión para crear un control específico de un diccionario no se siente muy natural, me gustaría usar un método de extensión.

    Algo como:

    public static class DropDownControl
    {
        public static DropDownControl<KeyValuePair<TKey,TValue>, TKey, TValue>
                Create<TKey,TValue>(IDictionary<TKey, TValue> value, string name)
        where TKey : IComparable
        {
            return new DropDownControl<KeyValuePair<TKey, TValue>, TKey, TValue>
                (name, value, pair => pair.Key, pair => pair.Value,
                key => value.ContainsKey(key)
            );
        }
    }

    Otra opción es la herencia, pero no me gusta mucho…

    public class DropDownControl<TKey, TValue> :
        DropDownControl<KeyValuePair<TKey, TValue>, TKey, TValue>
        where TKey : IComparable
    {
        public DropDownControl(IDictionary<TKey, TValue> lookup, string name)
            : base(name, lookup, pair => pair.Key, pair => pair.Value,
                key => lookup.ContainsKey(key)) { }
    }

    Esto añade complejidad y reduce su flexibilidad… yo no haría esto…

    General, parece que quiere a trabajar con sólo IDictionary<,> – yo me pregunto si no se puede simplificar el control de esta, y la fuerza de la no-diccionario personas que llaman se envuelven en un IDictionary<,> fachada?

    Bueno, yo estaba buscando una manera de hacer algo como C++ parcial de la plantilla de la especialización. Pero parece C# en la actualidad no se puede hacer eso (ni siquiera con trucos).
    Pero el IDictionary fachada es una buena idea de todos modos.
    En efecto; los genéricos no se prestan a la plantilla de la especialización

    OriginalEl autor Marc Gravell

  2. 0

    Si T siempre será KeyValuePair<TKey,TValue> no hay necesidad de ser un parámetro de tipo genérico. Usar sólo el tipo real todos los lugares de utilizar T.

    De lo contrario, si el tipo a veces, tiene que ser algo más, te sugiero que tal vez debería tener un tipo de base DropDownControl<TKey, TValue> : BaseControl con un campo protegido Helper del mismo tipo, y virtual implementaciones de casi todos los métodos que simplemente invocar a sus contrapartes en Helper; dentro de los que definen una clase derivada HeldAs<TPair> que invalida todos los métodos con «real» de las implementaciones.

    El constructor de DropDownControl<TKey,TValue> construiría una nueva instancia de DropDownControl<TKey,TValue>.HeldAs<KeyValuePair<TKey,TValue>> y almacenar una referencia a que en Helper. Fuera de código podría contener referencias de tipo DropDownControl<TKey,TValue> y utilizarlos sin necesidad de conocer o de cuidado de cómo las claves y los valores se llevaron a cabo. El código que se necesita para crear algo que las tiendas de cosas de una manera diferente y utiliza diferentes métodos para extraer las claves y los valores de llamar al constructor de DropDownControl<TKey,TValue>.HeldAs<actualStorageType>, pasando de las funciones que puede convertir actualStorageType claves o valores, según corresponda.

    Si cualquiera de los métodos de DropDownControl<TKey,TValue> se espera que pase this, entonces el constructor de DropDownControl<TKey,TValue>.HeldAs<TStorage> debe establecer Helper a sí mismo, pero el constructor del tipo base, después de la construcción de los derivados de tipo de instancia, debe establecer la derivada de la instancia de Helper referencia a sí mismo (la base de la clase de contenedor). Los métodos que pasaría this debe entonces pasar Helper. Que se asegurará de que cuando una clase derivada de la instancia es construido exclusivamente para el propósito de ser envuelto, el mundo exterior nunca recibirá una referencia a los derivados de la instancia, pero en lugar de siempre ve el contenedor.

    OriginalEl autor supercat

Dejar respuesta

Please enter your comment!
Please enter your name here