只包含可序列化对象的字典

6
我希望找到一种方法,确保只有可序列化的对象存储在C#字典中。
更具体地说,我想做类似于这样的事情:
Dictionary<String, ISerializable> serialDict = new Dictionary<String, ISerializable>();

问题在于我无法存储像整数、布尔值或字符串这样的基本类型。

有没有一种方法可以确保我的字典只包含可序列化的对象?

5个回答

4
我认为你无法在编译时完成此操作,但可以在运行时完成。如果您构建自己的类并从Dictionary<TKey, TValue>继承,则在类的构造函数中,您可以检查附加到TValue类型的属性,并确保其中一个是SerializableAttribute,否则会抛出异常。
所有标准原始类型(intbool等)都具有此属性。

谢谢您的洞察力,现在我觉得更清晰了。虽然我原本希望有一种编译时的解决方案,但这样也完全可以。 - LamdaComplex

2
需要考虑的一件事是,可序列化的类使用SerializableAttribute标记,而不是实现接口。来自MSDN的说明如下:

任何可能被序列化的类都必须标记为SerializableAttribute。如果一个类需要控制其序列化过程,则可以实现ISerializable接口。

您需要做的是创建自己的类,实现IDictionary接口,并且每次有人调用add方法时,使用反射检查传入的元素是否具有可序列化属性(如果没有,则抛出异常)。
代码如下:
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();
        }
    }
    .....
}

我也喜欢这个解决方案,正是我项目所需要的。谢谢。 - LamdaComplex

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
如果想要在这个字典中存储整数、布尔值和字符串,应该选择什么类型作为 TValue? - Amy B
@David 很好的观点,+1。这是不支持的。但我理解问题是询问者想要存储其中一种类型,而不是它们的组合。 - Mårten Wikström

1
一个解决方案是创建一个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;
       }
   }
}

剩下的部分留给读者自己练习,但基本上你需要创建一个适配器来使这些特定类型“适应”你的字典。

*另请参阅:数据契约序列化器支持的类型

**另请参阅:C#:使用反射在 .Net 中实例化泛型类


这似乎有些过度,因为可序列化的类(包括基元类型)已经标记了适当的属性。 - Roman

0

你考虑过对字典进行包装吗?

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

通过这种方式,您可以确保只有可序列化的对象和基本类型可以添加。


1
根据MSDN文档,只有当对象想要控制序列化过程时,它们才需要实现ISerializable接口。因此,并不是所有可序列化的对象都实现了该接口。 - Roman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接