2009-09-23 20 views
10

El código siguiente se compila, pero falla con un NullReferenceException:compilación C# diccionario inicializador inconsistencia

class Test 
{ 
    public Dictionary<string, string> Dictionary { get; set; } 
} 

static void Main(string[] args) 
{ 
    var x = new Test 
    { 
     Dictionary = // fails 
     { 
      { "key", "value" }, { "key2", "value2" } 
     } 
    }; 
} 

Si reemplaza la línea marcada 'falla' con lo siguiente, que funciona (como se esperaba):

Dictionary = new Dictionary<string, string> 

¿Hay algún propósito en la sintaxis fallida? ¿Se puede usar con éxito en algún otro caso? ¿O es esto un descuido en el compilador?

Respuesta

32

No, no es un error ... es una falla en su comprensión de la sintaxis de inicialización :)

La idea de la

Dictionary = { ... } 

es para los casos en que la persona que llama tiene acceso leer a una propiedad de colección, pero no escriba acceso. En otras palabras, situaciones como esta:

class Test 
{ 
    private readonly Dictionary<string, string> dictionary 
     = new Dictionary<string, string>(); 
    public Dictionary<string, string> Dictionary { get { return dictionary; } } 
} 

Básicamente terminan siendo llamadas a Agregar, pero sin crear primero una nueva colección. Por lo que este código:

Test test = new Test { Dictionary = { { "a", "b"}, {"c", "d" } }; 

es equivalente a:

Test tmp = new Test(); 
Dictionary<string, string> tmpDictionary = tmp.Dictionary; 
tmpDictionary.Add("a", "b"); 
tmpDictionary.Add("c", "d"); 
Test test = tmp; 

Un buen ejemplo de esto es útil es con la colección Controls para una interfaz de usuario. Usted puede hacer esto:

Form form = new Form 
{ 
    Controls = 
    { 
     new Button { Text = "Hi" }, 
     new TextBox { Text = "There" } 
    } 
}; 

pero no se podía establecer en realidad la propiedad Controls, porque es de sólo lectura.

+0

Así se usa para agregar elementos a un diccionario creado por el constructor; debería haberme dado cuenta de eso. Pero es un uso extraño del operador de iguales, ya que el efecto es agregar a lo que ya está en el diccionario (el constructor puede haber agregado elementos primero). –

+0

Más o menos, sí ... pero al mismo tiempo se usa para establecer los valores iniciales en la colección, por lo que encaja de esa manera. –

+0

Derecha. El 'nuevo' faltante debería haber sido una bandera roja ... pero como nunca había usado esta sintaxis, tomé el operador de iguales demasiado literalmente. –

0

Fracasa con una excepción de referencia nula porque ha declarado una variable (Diccionario) que no está seleccionada, por lo tanto, es nula.

Cuando intenta agregar las entradas con la sintaxis del inicializador, está intentando escribir datos en un objeto nulo.

Cuando reemplaza la línea con "= new Dictionary ...", está creando un nuevo objeto para que Dictionary for reference, y por lo tanto, puede agregarle entradas correctamente.

(En el ejemplo de Jon Skeet, la colección Controls ya debe haber sido creado por el formulario, por lo tanto, funciona bien)

+0

Sí, por supuesto. Mi pregunta era: ¿por qué permitir esta sintaxis? –

+0

Bastante justo.Jon respondió tu pregunta, así que pensé en completar la razón en caso de que no entendieras el error. –

4

Puede seguir utilizando la sintaxis que se desea en un constructor:

Dictionary<string, string> dictionary = new Dictionary<string, string> 
      { 
       {"a", "b"}, 
       {"c", "d"} 
      };