2010-02-12 13 views
14

Bien, entonces sé que es simple construir un método de fábrica que proporcione la funcionalidad; pero dado que Dictionary<TKey, TValue> es IEnumerable<KeyValuePair<TKey, TValue>>, ¿no debería tener un Ctor equivalente a, por ejemplo, List<T> 's ctor(IEnumerable<T> range)?¿Por qué el Diccionario <TKey, TValue> no tiene un IEnumerable <KeyValuePair <TKey, TValue >> ctor?

Es incluso más tonto dado que proporciona un Ctor que toma un IDictionary<TKey, TValue> como fuente, pero dado que esa interfaz también es IEnumerable<KeyValuePair<TKey, TValue>>, la opción IEnumerable seguramente tendría más sentido; a menos que la interfaz IEnumerable<> no existiera cuando se diseñó la clase por primera vez.

Se consigue de peor porque si nos fijamos en la implementación de la versión IDictionary del ctor - el diccionario de entrada se importa con el siguiente código:

foreach (KeyValuePair<TKey, TValue> pair in dictionary) 
{ 
    this.Add(pair.Key, pair.Value); 
} 

alguien pensar en una buena razón de por qué los diseñadores marco eligió la interfaz más específica cuando una interfaz base era todo lo que se requería?

Edición

@ Marcos Seeman sugiere que se trata de evitar excepciones siendo criados por duplicados de las llaves - que es probablemente cerca de la verdad - pero tenga en cuenta este ejemplo:

[TestMethod] 
[ExpectedException(typeof(ArgumentException))] 
public void How_To_Break_The_IDictionary_Ctor_Design_Decision() 
{ 
    Dictionary<string, string> dictionary = new Dictionary<string, string>(); 
    dictionary.Add("hello", "world"); 
    dictionary.Add("Hello", "world"); 

    Dictionary<string, string> dictionary2 = 
    new Dictionary<string, string>(dictionary, 
            StringComparer.CurrentCultureIgnoreCase); 
} 

que sé - la prueba está en reversa - pero por alguna razón, pensé que era mi punto mejor :)

Dado que el comparador de claves no es parte de la IDiction interfaz aria, puede nunca garantizar que el diccionario que está importando no generará claves duplicadas, y por lo tanto un ArgumentException, al construir el nuevo.

Ergo - también podría tener un constructor de IEnumerable que haga lo mismo.

+0

pedí lo mismo para guayaba recientemente: http://code.google.com/p/guava-libraries/issues/detail?id=320 – finnw

Respuesta

13

totalmente conjetura no oficial:

Si un constructor permitió una IEnumerable<KeyValuePair<TKey, TValue>> que habría sido capaz de suministrar varios elementos, con la misma clave y cuál sería el comportamiento esperado de eso?

E.g. que podría haber hecho algo como esto:

var kvps = new[] 
{ 
    new KeyValuePair<int, string>(1, "Foo"), 
    new KeyValuePair<int, string>(1, "Bar"), 
    new KeyValuePair<int, string>(1, "Baz")   
} 
var dic = new Dictionary<int, string>(kvps); 

Se podría argumentar que este debe ser simplemente una excepción para ser coherente con el comportamiento del método Add, pero yo supongo que el equipo de diseño pensó que sería una mayor fuente de confusión que realmente útil ...

+2

a medida que más en el mismo sentido, podemos ver que 'Dictionary' también 'carece' de un 'AddRange', ¿por una razón similar quizás? – AakashM

+1

Aunque esta podría no ser la razón oficial, es suficiente para justificar la ausencia del constructor 'IEnumerable >'. –

+5

+1 Ese es un buen punto, y probablemente bastante cercano a la verdad. Sin embargo, si esa fue la decisión de diseño, entonces es defectuosa: podría pasar una instancia de Dictionary que usa un IComparer menos restrictivo (p.el StringComparer predeterminado frente al mayúsculo) que el nuevo que todavía podría generar una excepción. Un IDictionary no necesariamente hace otra marca IDictionary. –

1
public static Dictionary<T, U> ToDictionary(
     this IEnumerable<KeyValuePair<T, U>> source) 
    { 
    return source.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); 
    } 
Cuestiones relacionadas