Сериализация .NET Runtime - PullRequest
       2

Сериализация .NET Runtime

5 голосов
/ 10 декабря 2010

Может кто-нибудь объяснить, в чем разница между наследованием от ISerializable интерфейса и объявлением вашего объекта как [Serializable]?

Я знаю, что в первом случае вы должны реализовать ISerializable члены интерфейса, в то время как во втором случае эта работа, вероятно, будет выполняться самим C #.

Но тогда для меня не имеет смысла следующее поведение:

public void Foo<T>() where T : ISerializable
{
   // Whatever
}

Теперь, если у меня есть какой-нибудь класс, подобный этому:

[Serializable]
public class Value
{
    public String Value { get; set; }
}

И, к сожалению, я не могу назвать свой X.Foo<Value>(), потому что компилятор говорит:

There is no implicit reference conversion from 'Value' to 'System.Runtime.Serialization.ISerializable'

Я почти уверен, что это мое неправильное понимание чего-то очевидного, поэтому, пожалуйста, укажите, что я делаю неправильно.


ОБНОВЛЕНИЕ (ВАЖНО :)

Как заставить оператор where T : ISerializable работать также с классом [Serializable]?Есть ли способ?

Я пытаюсь добиться ошибки времени компиляции, если предоставленный тип T не сериализуем (используя способ [Serializable] или ISerializable).

Очевидно, что моя текущая проверка обрабатывает только второй случай, так как мне сделать так, чтобы он обрабатывал оба из них?

Ответы [ 5 ]

4 голосов
/ 10 декабря 2010

Serializable - это просто атрибут, который вы помещаете в класс, чтобы такие классы, как SoapFormatter знали (через отражение), что его можно сериализовать. Украшение класса с атрибутом не делает классом, реализующим интерфейс, поэтому компилятор жалуется в вашем случае. Если память служит, то реализуется ISerializable, если требуется больший контроль над процессом сериализации.

3 голосов
/ 10 декабря 2010

Чтобы ответить на ваше обновление: вы не можете наложить универсальное ограничение на наличие атрибута.

Следующее, что вы можете сделать, это вызвать исключение (очевидно, во время выполнения, а не при компиляции-время).Для универсального метода это выглядело бы примерно так:

public void Foo<T>()
{
    if (!typeof (ISerializable).IsAssignableFrom(typeof (T))
        || !typeof (T).GetCustomAttributes(true).OfType<SerializableAttribute>().Any())
    {
        throw new InvalidOperationException(string.Format("Type {0} is not serializable.", typeof (T).FullName));
    }
}

Для универсального класса это можно сделать в статическом конструкторе (происходит быстрее):

public class Foo<T>
{
    static Foo()
    {
        if (!typeof(ISerializable).IsAssignableFrom(typeof(T))
            || !typeof(T).GetCustomAttributes(true).OfType<SerializableAttribute>().Any())
        {
            throw new InvalidOperationException(string.Format("Type {0} is not serializable.", typeof(T).FullName));
        }
    }
}
2 голосов
/ 10 декабря 2010

[Serializable] это просто атрибут. Это не заставит ваш класс реализовать интерфейс ISerializable. Все, что он делает, указывает платформе .NET, что ваш класс можно сериализовать.

Поэтому, когда вы попытаетесь сериализовать ваш класс, фреймворк проверит, как он должен это делать. Если интерфейс ISerializable отсутствует, он попытается использовать встроенные сериализаторы и позаботится об этом за вас. Если вы явно реализовали ISerializable, то он будет использовать вашу собственную реализацию сериализации.

Вот почему иногда вам приходится писать классы типа

[Serializable]
public class MyClass : ISerializable
{}

К сожалению, вы не можете делать то, что хотите, и выполнять проверку во время компиляции для [Serializable] или ISerializable. Лучшее, что вы можете сделать, - это проверить во время выполнения внутри метода, является ли передаваемый тип сериализуемым или нет (либо путем отражения, либо путем перехвата исключения сериализации).

В качестве альтернативы вы можете принять соглашение, согласно которому все ваши сериализуемые типы должны реализовывать вашу собственную версию ISerializable:

public interface ICanBeSerialized
{
    // this interface is left intentionally blank
}

public class Value : ICanBeSerialized
{
    // do whatever
}

public class MyClass 
{
    public void Foo<T>() where T : ICanBeSerialized
    { }
}
0 голосов
/ 10 декабря 2010

ISerializeable позволяет объекту создавать свою собственную (де) сериализацию.Вы можете использовать это для сериализации глубоких структур данных в плоскую версию и воссоздать ее при десериализации или при желании сериализовать определенные структуры в простые значения (например, Color).

Как правило, встроенного процесса сериализации достаточноВпрочем.

0 голосов
/ 10 декабря 2010

Атрибут simple указывает, что класс можно сериализовать.Реализация ISerailizable переопределит процесс сериализации.Ваш класс Value должен реализовывать интерфейс ISerializable.

public class Value : ISerializable 
{
    public String Value { get; set; }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...