2011-08-12 12 views
6

Szukam sposobu, aby zapewnić, że tylko obiekty serializowalne są przechowywane w słowniku w języku C#.Słownik zawierający tylko obiekty nadające się do szeregowania

Aby być bardziej konkretny szukam coś podobnego do tego:

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

Problemem jest to, że nie można zapisać prymitywnych typów jak liczb całkowitych, wartości logiczne lub łańcuchów.

Czy istnieje sposób na zapewnienie, że mój słownik zawiera tylko obiekty, które można serializować?

Odpowiedz

4

Nie sądzę, że można to zrobić podczas kompilacji, ale można to zrobić w czasie wykonywania. Jeśli zbudujesz własną klasę wywodzącą się z Dictionary<TKey, TValue>, wówczas w konstruktorze twojej klasy możesz sprawdzić atrybuty dołączone do typu TValue i upewnić się, że SerializableAttribute jest jednym z nich, inaczej wyrzuć wyjątek.

Wszystkie standardowe typy podstawowe (int, bool itp.) Mają ten atrybut.

+0

Dziękuję za zrozumienie, to ma większy sens. Miałem nadzieję na rozwiązanie w czasie kompilacji, ale będzie działało dobrze. – LamdaComplex

0

A co z zawijaniem słownika?

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 ... 
} 

W ten sposób masz pewność, że można dodać tylko obiekty możliwe do internowania i typy pierwotne.

+1

W dokumentacji MSDN obiekty muszą jedynie implementować interfejs ISerializowalny, jeśli chcą kontrolować proces serializacji. Więc nie wszystkie obiekty serializowalne implementują ten interfejs. – 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

Jeśli ktoś chciał przechowywać ints, booleans i stringi w tym słowniku, jaki typ powinien zostać wybrany jako TValue? –

+0

@David Dobry punkt, +1. To nie jest obsługiwane. Ale przeczytałem pytanie, jakby pytający chciał przechowywać jeden z tych typów, a nie ich kombinację. –

2

Jedną rzeczą do rozważenia jest to, że w klasach, które są oznaczone serializable z SerializableAttribute w przeciwieństwie do realizacji interfejsu. Od MSDN:

dowolnej klasy, które mogą być szeregowane musi być oznaczone SerializableAttribute. Jeśli klasa musi kontrolować proces serializacji , może zaimplementować interfejs ISerializable.

Co trzeba zrobić, to stworzyć własną klasę, która implementuje interfejs IDictioanry i za każdym razem ktoś dzwoni dodać, użyć refleksji, by sprawdzić, czy element przekazany posiada atrybut można zaszeregować (a wyjątek, jeśli nie robi "t).

kod będzie wyglądał jak

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

Podoba mi się również to rozwiązanie, to jest właśnie to, czego potrzebuję do mojego projektu. Dziękuję Ci. – LamdaComplex

1

jedna odpowiedź byłoby stworzyć SerializablePrimative klasy otoki.

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; 
     } 
    } 
} 

Resztę pozostawiamy jako ćwiczenie czytelnikowi, ale w zasadzie tworzymy adapter, aby te określone typy "pasowały" do twojego słownika.

* Zobacz także: Types Supported by the Data Contract Serializer

** Patrz również: C#: Using Reflection to Instantiate a Generic Class in .Net

+0

Wygląda na to, że zbyt duże klasy serializowalne (w tym klasy podstawowe) są już oznaczone odpowiednim atrybutem. – R0MANARMY

Powiązane problemy