2010-07-20 22 views
6

Tôi có một lớp hiện có để tuần tự hóa và deserializing các đối tượng đến/từ XML. Đó là một lớp chung với một tham số kiểu đơn T chỉ có ràng buộc là where T : IXmlSerializable. Tuy nhiên, tôi vẫn muốn có thể sử dụng lớp này trên các lớp không thực hiện IXmlSerializable nhưng có thuộc tính [Serializable]. Làm thế nào tôi có thể đi về việc này?Lớp tiện ích serialization C# generic

Từ lớp chung tôi:

public static class XmlSerializationUtils<T> where T : IXmlSerializable 
{ 
    public static T DeserializeXml(XmlDocument xml) { ... } 
    public static XmlDocument SerializeToXml(T toSerialize) { ... } 
} 

tôi thấy this discussion nhưng không có giải pháp nào đó, chỉ là tôi không thể làm where T : Serializable. Cố gắng làm where T : SerializableAttribute làm cho Visual Studio nói "Không thể sử dụng lớp niêm phong 'System.SerializableAttribute' như ràng buộc tham số kiểu".

Edit: dựa trên Stephen's answer, tôi loại bỏ các hạn chế về XmlSerializationUtils<T> và thêm vào constructor tĩnh này:

static XmlSerializationUtils() 
{ 
    Type type = typeof(T); 
    bool hasAttribute = null != Attribute.GetCustomAttribute(type, 
     typeof(SerializableAttribute)); 
    bool implementsInterface = 
     null != type.GetInterface(typeof(IXmlSerializable).FullName); 
    if (!hasAttribute && !implementsInterface) 
    { 
     throw new ArgumentException(
      "Cannot use XmlSerializationUtils on class " + type.Name + 
      " because it does not have the Serializable attribute " + 
      " and it does not implement IXmlSerializable" 
     ); 
    } 
} 

Trả lời

6

Bạn không thể đòi hỏi một thuộc tính như một phần của Generics. Tuy nhiên, bạn có thể cung cấp một hàm tạo tĩnh để kiểm tra nó và ném nếu nó không được tìm thấy.

5

tôi chỉ muốn loại bỏ các loại hạn chế và bắt SerializationException khi loại không serialize hoặc deserialize đúng cách ... Trong thực tế, điều này cho phép Serialize chung của bạn và Deserialize phương pháp để chấp nhận một định dạng

public enum Formatter { Binary, Xml } 

có thể kiểm soát việc tuần tự hóa là nhị phân hay Xml

public class Serialization 
{ 
    public enum Formatter { Binary, Xml } 

    #region Serialization methods 
    public static void Serialize2File<T>(T obj, string pathSpec, 
     Formatter formatter) 
    { 
     try 
     { 
      switch (formatter) 
      { 
       case (Formatter.Binary): 
        using (var fs = new FileStream(pathSpec, FileMode.Create, 
             FileAccess.Write, FileShare.Write)) 
         (new BinaryFormatter()).Serialize(fs, obj); 
        break; 

       case (Formatter.Xml): 
        var serializer = new XmlSerializer(typeof(T)); 
        TextWriter textWriter = new StreamWriter(pathSpec); 
        serializer.Serialize(textWriter, obj); 
        textWriter.Close(); 
        break; 

       default: 
        throw new MyCustomException("Invalid Formatter option"); 
      } 
     } 
     catch (SerializationException sX) 
     { 
      var errMsg = String.Format(
       "Unable to serialize {0} into file {1}", 
       obj, pathSpec); 
      throw new MyCustomException(errMsg, sX); 
     } 
    } 
    public static T DeSerializeFromFile<T>(string pathSpec, 
     Formatter formatter) where T : class 
    { 
     try 
     { 
      switch (formatter) 
      { 
       case (Formatter.Binary): 
        using (var strm = new FileStream(pathSpec, 
             FileMode.Open, FileAccess.Read)) 
        { 
         IFormatter fmt = new BinaryFormatter(); 
         var o = fmt.Deserialize(strm); 
         if (!(o is T)) 
          throw new ArgumentException("Bad Data File"); 
         return o as T; 
        } 

       case (Formatter.Xml): 
        var serializer = new XmlSerializer(typeof(T)); 
        TextReader rdr = new StreamReader(pathSpec); 
        return (T)serializer.Deserialize(rdr); 

       default: 
        throw new MyCustomException("Invalid Formatter option"); 
      } 
     } 
     catch (SerializationException sX) 
     { 
      var errMsg = String.Format(
       "Unable to deserialize {0} from file {1}", 
       typeof(T), pathSpec); 
      throw new MyCustomException(errMsg, sX); 
     } 
    } 
    #endregion Serialization methods 
} 
+0

Đó không phải là giải pháp không hợp lý. –

+0

Vâng, tôi đồng ý, nó đang được một nhà phát triển sử dụng, những người không biết liệu lớp anh ta đang cố gắng nối tiếp có thể thay đổi được không, nếu anh ta sử dụng sai nó là ngoại lệ, bạn không thể loại bỏ mọi lỗi có thể xảy ra trong thời gian biên dịch. –

+0

@Ben: Chúng tôi không thể luôn luôn làm như vậy, nhưng chúng tôi chắc chắn nên cố gắng để bắt lỗi sớm và thường xuyên. Trong trường hợp này, chúng ta không thể bắt nó ở thời gian biên dịch, nhưng nếu chúng ta sử dụng thủ thuật xây dựng tĩnh, chúng ta có thể bắt nó vào lúc bắt đầu chạy (nghĩa là kiểm tra khói sau biên dịch sẽ không bỏ lỡ nó). –

8

Bạn có thể kiểm tra xem loại có thể tuần tự hóa không bằng thuộc tính IsSerializable của Loại đối tượng.

myObj.GetType().IsSerializable 

Như đã đề cập, điều này không thể thêm làm ràng buộc chung, nhưng rất có thể sẽ được kiểm tra trong hàm tạo.

+0

Điều này tốt hơn là kiểm tra thuộc tính. Cảm ơn. –

+0

Hm. Giải pháp hiện tại của tôi (trong câu hỏi của tôi) kiểm tra xem liệu 'IXmlSerializable' hoặc' [Serializable] 'có áp dụng cho lớp đã cho' T' hay không. Tài khoản 'IsSerializable' cho cả hai? –

+0

Rõ ràng. Xem http://msdn.microsoft.com/en-us/library/system.type.isserializable.aspx –

Các vấn đề liên quan