Как проверить, сериализуем ли объект в C#

Я ищу простой способ проверить, сериализуем ли объект в C#.

Как мы знаем, вы делаете объект сериализуемым, реализуя интерфейс ISerializable или помещая [Сериализуемый] в начало класса.

Я ищу быстрый способ проверить это без необходимости отражать класс, чтобы получить его атрибуты. Интерфейс был бы быстрым, используя оператор является.

Используя предложение @Flard, это код, который я придумал, крик, есть ли лучший способ.

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

Или, что еще лучше, просто получите тип объекта и затем используйте свойство IsSerializable для этого типа:

typeof(T).IsSerializable

Помните, хотя это кажется только классом, с которым мы имеем дело, если класс содержит другие классы, вы, вероятно, захотите проверить их все или попытаться сериализовать и дождаться ошибок, как указал @pb.

Извините, это не удается, когда поле в obj не сериализуемо, см. Мой образец.

Paul van Brenk 17.09.2008 14:26

Я думаю, что это намного лучший подход: stackoverflow.com/questions/236599/…

xero 02.08.2011 23:02

Утверждение «вы делаете объект сериализуемым, реализуя интерфейс ISerializable или помещая [Serializable] в начало класса», неверно. Чтобы объект можно было сериализовать, в его классе должен быть объявлен атрибут SerializableAttribute. Внедрение ISerializable только дает вам больший контроль над процессом.

Mishax 29.08.2013 09:39
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
95
3
67 239
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

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

Наверное, предполагает отражение под водой, но самый простой способ?

Вам нужно будет проверить все типы в графе сериализуемых объектов на предмет сериализуемого атрибута. Самый простой способ - попытаться сериализовать объект и перехватить исключение. (Но это не самое чистое решение). Type.IsSerializable и проверка атрибута serializalbe не учитывают график.

Образец

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

Если стоимость не слишком велика, я думаю, что этот подход является лучшим. Он может проверять различные требования к сериализации (двоичный, xml). Кроме того, у объекта может быть общий член, который может быть заменен унаследованными типами классов, которые могут нарушать сериализацию и могут изменяться во время выполнения. Список (Of baseclass) может иметь добавленные элементы подкласса A, который не является сериализуемым, где базовый класс и подклассB сериализуемы.

VoteCoffee 18.05.2020 15:09

В этом ответе используется клонирование, чтобы проверить, может ли сериализация проходить туда и обратно. В некоторых случаях это может быть излишним, хотя не ожидается, что сериализация установит некоторые члены: stackoverflow.com/questions/236599/…

VoteCoffee 18.05.2020 15:12
Ответ принят как подходящий

У вас есть прекрасный отель класса Type под названием IsSerializable.

Это просто проинформирует вас, прикреплен ли к вашему классу атрибут Serializable.

Fatema 09.12.2010 12:58

его точка зрения состоит в том, что члены этого объекта могут быть не сериализуемыми, даже если содержащий тип. верно? Разве это не тот случай, когда мы должны рекурсивно углубляться в элементы этих объектов и проверять каждый из них, если не просто пытаться сериализовать его и посмотреть, не сработает ли он?

Brian Sweeney 26.01.2011 21:34

Например, для List <SomeDTO> IsSerializable истинно, даже если SomeDTO НЕ сериализуем.

Simon Dowdeswell 15.03.2017 03:30

Вот вариант 3.5, который делает его доступным для всех классов, использующих метод расширения.

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

Используйте Type.IsSerializable, как указывали другие.

Вероятно, не стоит пытаться отразить и проверить, все ли члены в графе объектов сериализуемы.

Член может быть объявлен как сериализуемый тип, но на самом деле может быть создан как производный тип, который не является сериализуемым, как в следующем надуманном примере:

[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

Следовательно, даже если вы определите, что конкретный экземпляр вашего типа является сериализуемым, вы, как правило, не можете быть уверены, что это будет верно для всех экземпляров.

Это старый вопрос, который, возможно, потребуется обновить для .NET 3.5+. Type.IsSerializable может фактически вернуть false, если класс использует атрибут DataContract. Вот фрагмент, который я использую, если он воняет, дайте мне знать :)

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

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

}

Старый вопрос и старые ответы, но это ОЧЕНЬ верно! Type.IsSerializable - это частично функциональное решение. Фактически, учитывая, сколько людей используют WCF и DataContracts в наши дни, это на самом деле очень плохое решение!

Jaxidian 18.10.2012 20:52

Что, если obj имеет значение null?

N73k 02.08.2018 05:51

@ N73k сделать проверку null и вернуть, если true?

FredM 19.06.2019 13:15

Объект исключения может быть сериализуемым, но с использованием другого исключения, которого нет. Это то, что у меня было только что с WCF System.ServiceModel.FaultException: FaultException можно сериализовать, а ExceptionDetail - нет!

Итак, я использую следующее:

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

Я взял ответ на этот вопрос и ответ здесь и изменил его, чтобы вы получили список типов, которые не сериализуемы. Таким образом, вы легко узнаете, какие из них отметить.

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

А потом вы называете это ...

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

Когда он запускается, nonSerializableTypes будет иметь список. Может быть лучший способ сделать это, чем передать пустой список рекурсивному методу. Кто-нибудь поправьте меня, если так.

Мое решение в VB.NET:

Для объектов:

''' <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

Для типов:

''' <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

Мне это нравится, потому что, как отметили другие респонденты, атрибуты и свойства ничего не значат. Вы можете прикрепить атрибут ISerializable к любому классу, Type.IsSerializable неисправен, но самое главное: объекты, на которые он ссылается, могут фактически быть несериализуемыми подклассами. Единственный способ - попробовать. Но я бы немного доработал ее до функции TrySerialize, чтобы успешную сериализацию не нужно было выполнять дважды.

Wolfzoon 23.12.2020 01:53

Другие вопросы по теме