2011-08-12 14 views
6

Estoy buscando una forma de garantizar que solo los objetos serializables se almacenen en un diccionario en C#.Diccionario que contiene solo objetos serializables

Para ser más específico que estoy buscando hacer algo similar a esto:

Dictionary<String, ISerializable> serialDict = new Dictionary<String, ISerializable>(); 

El problema con esto es que no puedo almacenar tipos primitivos como enteros, booleanos, o cadenas.

¿Hay alguna forma de garantizar que mi diccionario contenga solo los objetos que se pueden serializar?

Respuesta

4

No creo que pueda hacer esto en tiempo de compilación, pero puede hacerlo en tiempo de ejecución. Si construye su propia clase derivada de Dictionary<TKey, TValue>, entonces en el constructor de su clase, puede verificar los atributos adjuntos al tipo TValue, y asegúrese de que SerializableAttribute es uno de ellos, sino haga una excepción.

Todos los tipos primitivos estándar (int, bool, etc.) tienen este atributo.

+0

Gracias por la información, esto tiene más sentido. Esperaba una solución de tiempo de compilación, pero esto funcionará muy bien. – LamdaComplex

0

¿Qué tal envolver su diccionario?

class SomeClass { 

    Dictionary<string,object> d; 
    // add ISerializable 
    public void Add(string key, ISerializable value) { 
     d[key] = value; 
    } 
    // add primitive types 
    public void Add(string key, bool value) { 
     d[key] = value; 
    } 
    public void Add(string key, int value) { 
     d[key] = value; 
    } 
    // etc ... 
} 

De esta manera, está seguro de que solo se pueden agregar objetos y tipos primitivos ISerializable.

+1

Según la documentación de MSDN, los objetos solo necesitan implementar la interfaz ISerializable si desean controlar el proceso de serialización. Entonces, no todos los objetos serializables implementan esta interfaz. – R0MANARMY

1
[Serializable] 
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue> 
{ 
    static SerializableDictionary() 
    { 
     AssertSerializable(typeof(TKey)); 
     AssertSerializable(typeof(TValue)); 
    } 

    static void AssertSerializable(Type t) 
    { 
     if (!t.IsSerializable) 
     { 
      throw new NotSupportedException(string.Format(
       "{0} is not serializable", t.Name)); 
     } 
    } 
} 
+1

Si uno quisiera almacenar ints, booleans y cadenas en este diccionario, ¿qué tipo debería elegirse como TValue? –

+0

@David Buen punto, +1. Eso no es compatible. Pero leí la pregunta como si el asker quisiera almacenar uno de estos tipos, no una combinación de ellos. –

2

Una cosa a tener en cuenta es que en las clases que son serializable están etiquetadas con el SerializableAttribute en oposición a la implementación de una interfaz. De MSDN:

Cualquier clase que podrían ser serializado debe ser marcado con el SerializableAttribute. Si una clase necesita controlar su proceso de serialización , puede implementar la interfaz ISerializable.

Lo que tendría que hacer es hacer su propia clase que implementa la interfaz IDictioanry y cada vez que alguien llama a agregar, utilizar la reflexión para comprobar si el elemento aprobada en cuenta un atributo serializable (y lanzar una excepción si él doesn 't).

código sería algo así como

class MyDictionary<TKey, TValue> : IDictionary<TKey, TValue> 
{ 
    private Dictionary<TKey, TValue> d; 

    public void Add(TKey key, TValue value) 
    { 
     if(value.GetType().IsSerializable) 
     { 
      d.Add(key, value); 
     } 
     else 
     { 
      throw new ArgumentException(); 
     } 
    } 
    ..... 
} 
+0

También me gusta esta solución, es justo lo que necesito para mi proyecto. Gracias. – LamdaComplex

1

Una respuesta sería la creación de una clase contenedora SerializablePrimative.

class SerializablePrimative<T> : ISerializable { 
    private T val = default(); 

    private SerializablePrimative(T newVal){ 
     val = newVal; 
    } 

    public static boolean IsSupported(Object o){ 
     if (o == null){ 
      return false; 
     }else{ 
      return IsSupported(o.GetType()); 
     } 
    } 

    public static boolean IsSupported(Type t){ 
     if (// you want to support* ...) 
     { 
      return true; 
     } 
     else 
     { 
     return false; 
     } 
    } 

    public static SerializablePrimative GetSerializable(Object o){ 
     if (IsSupported(o)){ 
      return //Intstatiate via Reflection ** 
     }else { 
      return null; 
     } 
    } 
} 

El resto se deja como ejercicio para el lector, pero, básicamente, su creación de un adaptador para hacer estos ciertos tipos "ajuste" de su diccionario.

* Véase también: Types Supported by the Data Contract Serializer

** Ver también: C#: Using Reflection to Instantiate a Generic Class in .Net

+0

Esto parece excesivo dado que las clases serializables (incluidas las primitivas) ya están etiquetadas con el atributo apropiado. – R0MANARMY

Cuestiones relacionadas