C # 'da bir nesnenin serileştirilebilir olup olmadığı nasıl kontrol edilir


94

C # 'da bir nesnenin serileştirilebilir olup olmadığını kontrol etmenin kolay bir yolunu arıyorum.

Bildiğimiz gibi, ISerializable arabirimini uygulayarak veya [Serializable] 'ı sınıfın en üstüne yerleştirerek bir nesneyi serileştirilebilir hale getirirsiniz .

Aradığım şey, niteliklerini elde etmek için sınıfı yansıtmak zorunda kalmadan bunu kontrol etmenin hızlı bir yolu. Arayüz, is deyimi kullanarak hızlı olacaktır .

@ Flard'ın önerisini kullanarak bulduğum kod bu, çığlık daha iyi bir yol var mı?

private static bool IsSerializable(T obj)
{
    return ((obj is ISerializable) || (Attribute.IsDefined(typeof (T), typeof (SerializableAttribute))));
}

Veya daha da iyisi, sadece nesnenin türünü alın ve ardından tür üzerinde IsSerializable özelliğini kullanın:

typeof(T).IsSerializable

Unutmayın, bunun sadece uğraştığımız sınıf gibi göründüğünü unutmayın, eğer sınıf muhtemelen hepsini kontrol etmek veya denemek ve serileştirmek ve @pb'nin işaret ettiği gibi hataları beklemek isteyeceğiniz diğer sınıfları içeriyorsa.


1
Nesnedeki bir alan serileştirilebilir olmadığında başarısız olan üzgünüm, örneğime bakın.
Paul van Brenk

Bunun çok daha iyi bir yaklaşım olduğunu düşünüyorum: stackoverflow.com/questions/236599/…
xero

"ISerializable arabirimini uygulayarak veya [Serializable] öğesini sınıfın en üstüne yerleştirerek bir nesneyi serileştirilebilir hale getirirsiniz" ifadesi yanlıştır. Bir nesnenin serileştirilebilir olması için, sınıfının SerializableAttribute öğesini bildirmesi gerekir. ISerializable'ı uygulamak, size yalnızca süreç üzerinde daha fazla kontrol sağlar.
Mishax

Yanıtlar:


115

TypeSınıfta aradığınız güzel bir mülkün var IsSerializable.


7
Bu, sınıfınıza Seri hale getirilebilir özelliği eklenip eklenmediğini size bildirecektir.
Fatema

37
Onun amacı, bu nesnenin üyelerinin, içeren tür olsa bile serileştirilemeyebileceğidir. sağ? bu nesnelerin üyelerini özyinelemeli olarak incelemek ve her birini kontrol etmek zorunda değil miyiz, sadece onu serileştirmeye çalışıp başarısız olup olmadığını görmek değil mi?
Brian Sweeney

3
Örneğin, <SomeDTO> Listesi için IsSerializable, SomeDTO serileştirilebilir OLMADIĞINDA bile doğrudur
Simon Dowdeswell

43

Serileştirilebilir öznitelik için serileştirilen nesnelerin grafiğindeki tüm türleri kontrol etmeniz gerekecektir. En kolay yol, nesneyi serileştirmeye ve istisnayı yakalamaya çalışmaktır. (Ama bu en temiz çözüm değil). Type.IsSerializable ve serializalbe özniteliğinin kontrol edilmesi grafiği hesaba katmaz.

Örneklem

[Serializable]
public class A
{
    public B B = new B();
}

public class B
{
   public string a = "b";
}

[Serializable]
public class C
{
    public D D = new D();
}

[Serializable]
public class D
{
    public string d = "D";
}


class Program
{
    static void Main(string[] args)
    {

        var a = typeof(A);

        var aa = new A();

        Console.WriteLine("A: {0}", a.IsSerializable);  // true (WRONG!)

        var c = typeof(C);

        Console.WriteLine("C: {0}", c.IsSerializable); //true

        var form = new BinaryFormatter();
        // throws
        form.Serialize(new MemoryStream(), aa);
    }
}

Maliyet çok yüksek değilse, bu yaklaşımın en iyisi olduğunu düşünüyorum. Farklı serileştirme gereksinimlerini (ikili, xml) kontrol edebilir. Ayrıca, bir nesnenin, serileştirmeyi bozabilecek ve çalışma zamanında değişebilecek miras alınan sınıf türleriyle değiştirilebilen genel bir üyesi olabilir. Listede (Temel sınıfın) alt sınıfı A'nın eklenmiş öğeleri olabilir, bu da serileştirilemez, burada temel sınıf ve alt sınıf B serileştirilebilir.
VoteCoffee

Bu cevap, serileştirmenin geri dönüş yapıp yapamayacağını kontrol etmek için klonlamayı kullanır. Serileştirmenin bazı üyeleri ayarlaması beklenmese de bazı durumlarda aşırı olabilir: stackoverflow.com/questions/236599/…
VoteCoffee

18

Bu eski bir sorudur ve .NET 3.5+ için güncellenmesi gerekebilir. Type.IsSerializable, sınıf DataContract özniteliğini kullanıyorsa aslında yanlış döndürebilir. İşte kullandığım bir pasaj, kokuyorsa bana haber ver :)

public static bool IsSerializable(this object obj)
{
    Type t = obj.GetType();

     return  Attribute.IsDefined(t, typeof(DataContractAttribute)) || t.IsSerializable || (obj is IXmlSerializable)

}

1
Eski soru ve eski cevaplar ama bu ÇOK doğru! Type.IsSerializable yalnızca kısmen işlevsel bir çözümdür. Aslında, bugünlerde kaç kişinin WCF ve DataContracts kullandığı göz önüne alındığında, bu aslında çok kötü bir çözüm!
Jaxidian

Ya obj null olarak gelirse?
N73k

@ N73k bir nullkontrol yapın ve eğer iade true?
FredM

9

Diğerlerinin de belirttiği gibi Type.IsSerializable kullanın.

Nesne grafiğindeki tüm üyelerin serileştirilebilir olup olmadığını yansıtmaya ve kontrol etmeye muhtemelen değmez.

Bir üye, serileştirilebilir bir tür olarak bildirilebilir, ancak aslında aşağıdaki hazır örnekte olduğu gibi serileştirilebilir olmayan bir türetilmiş tür olarak başlatılabilir:

[Serializable]
public class MyClass
{
   public Exception TheException; // serializable
}

public class MyNonSerializableException : Exception
{
...
}

...
MyClass myClass = new MyClass();
myClass.TheException = new MyNonSerializableException();
// myClass now has a non-serializable member

Bu nedenle, türünüzün belirli bir örneğinin serileştirilebilir olduğunu belirleseniz bile, genel olarak bunun tüm örnekler için geçerli olacağından emin olamazsınız.


6
Attribute.IsDefined(typeof (YourClass), typeof (SerializableAttribute));

Muhtemelen su altında yansımayı içerir, ancak en basit yol?


5

Burada, bir uzantı yöntemi kullanan tüm sınıflar için kullanılabilir hale getiren bir 3.5 varyasyonu var.

public static bool IsSerializable(this object obj)
{
    if (obj is ISerializable)
        return true;
    return Attribute.IsDefined(obj.GetType(), typeof(SerializableAttribute));
}

2

Bu soru ve cevabı üzerinde cevabını aldı burada ve Seri hale getirilebilir olmadığı türlerinin bir listesi olsun öyle güncellenmiştir. Bu şekilde hangilerini işaretleyeceğinizi kolayca bilebilirsiniz.

    private static void NonSerializableTypesOfParentType(Type type, List<string> nonSerializableTypes)
    {
        // base case
        if (type.IsValueType || type == typeof(string)) return;

        if (!IsSerializable(type))
            nonSerializableTypes.Add(type.Name);

        foreach (var propertyInfo in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
        {
            if (propertyInfo.PropertyType.IsGenericType)
            {
                foreach (var genericArgument in propertyInfo.PropertyType.GetGenericArguments())
                {
                    if (genericArgument == type) continue; // base case for circularly referenced properties
                    NonSerializableTypesOfParentType(genericArgument, nonSerializableTypes);
                }
            }
            else if (propertyInfo.GetType() != type) // base case for circularly referenced properties
                NonSerializableTypesOfParentType(propertyInfo.PropertyType, nonSerializableTypes);
        }
    }

    private static bool IsSerializable(Type type)
    {
        return (Attribute.IsDefined(type, typeof(SerializableAttribute)));
        //return ((type is ISerializable) || (Attribute.IsDefined(type, typeof(SerializableAttribute))));
    }

Ve sonra ona ...

    List<string> nonSerializableTypes = new List<string>();
    NonSerializableTypesOfParentType(aType, nonSerializableTypes);

Çalıştırıldığında, nonSerializableTypes listeye sahip olacaktır. Bunu yapmanın boş bir Listeyi özyinelemeli yönteme geçirmekten daha iyi bir yolu olabilir. Öyleyse biri beni düzeltsin.


0

İstisna nesnesi serileştirilebilir, ancak olmayan başka bir istisna kullanıyor olabilir. WCF System.ServiceModel.FaultException ile sahip olduğum şey buydu: FaultException serileştirilebilir ancak ExceptionDetail değil!

Bu yüzden aşağıdakileri kullanıyorum:

// Check if the exception is serializable and also the specific ones if generic
var exceptionType = ex.GetType();
var allSerializable = exceptionType.IsSerializable;
if (exceptionType.IsGenericType)
    {
        Type[] typeArguments = exceptionType.GetGenericArguments();
        allSerializable = typeArguments.Aggregate(allSerializable, (current, tParam) => current & tParam.IsSerializable);
    }
 if (!allSerializable)
    {
        // Create a new Exception for not serializable exceptions!
        ex = new Exception(ex.Message);
    }

0

Çözümüm, VB.NET'te:

Nesneler için:

''' <summary>
''' Determines whether an object can be serialized.
''' </summary>
''' <param name="Object">The object.</param>
''' <returns><c>true</c> if object can be serialized; otherwise, <c>false</c>.</returns>
Private Function IsObjectSerializable(ByVal [Object] As Object,
                                      Optional ByVal SerializationFormat As SerializationFormat =
                                                                            SerializationFormat.Xml) As Boolean

    Dim Serializer As Object

    Using fs As New IO.MemoryStream

        Select Case SerializationFormat

            Case Data.SerializationFormat.Binary
                Serializer = New Runtime.Serialization.Formatters.Binary.BinaryFormatter()

            Case Data.SerializationFormat.Xml
                Serializer = New Xml.Serialization.XmlSerializer([Object].GetType)

            Case Else
                Throw New ArgumentException("Invalid SerializationFormat", SerializationFormat)

        End Select

        Try
            Serializer.Serialize(fs, [Object])
            Return True

        Catch ex As InvalidOperationException
            Return False

        End Try

    End Using ' fs As New MemoryStream

End Function

Türler İçin:

''' <summary>
''' Determines whether a Type can be serialized.
''' </summary>
''' <typeparam name="T"></typeparam>
''' <returns><c>true</c> if Type can be serialized; otherwise, <c>false</c>.</returns>
Private Function IsTypeSerializable(Of T)() As Boolean

    Return Attribute.IsDefined(GetType(T), GetType(SerializableAttribute))

End Function

''' <summary>
''' Determines whether a Type can be serialized.
''' </summary>
''' <typeparam name="T"></typeparam>
''' <param name="Type">The Type.</param>
''' <returns><c>true</c> if Type can be serialized; otherwise, <c>false</c>.</returns>
Private Function IsTypeSerializable(Of T)(ByVal Type As T) As Boolean

    Return Attribute.IsDefined(GetType(T), GetType(SerializableAttribute))

End Function
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.