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

<p>я ищу простой способ проверить, является ли объект в c # сериализуемым.</p><p>как мы знаем, вы делаете сериализуемый объект, реализуя интерфейс <em>iserializable</em> или помещая <em>[serializable]</em> вверху класса.</p><p>то, что я ищу, это быстрый способ проверить это без необходимости отражать класс, чтобы получить его атрибуты. интерфейс будет быстрым, используя оператор <em>is</em>.</p><p>используя предложение @ flard, это код, который я придумал, кричать, что есть лучший способ.</p><pre><code>private static bool isserializable(t obj) { return ((obj is iserializable) || (attribute.isdefined(typeof (t), typeof (serializableattribute)))); } </code></pre><p>или еще лучше просто получить тип объекта и затем использовать свойство isserializable для типа:</p><pre><code>typeof(t).isserializable </code></pre><p>помните, что это кажется только тем классом, с которым мы имеем дело, если класс содержит другие классы, вы, вероятно, захотите проверить их все или попробовать и сериализовать и ждать ошибок, как указывал @pb.</p>

<p>у вас есть прекрасное свойство в классе <code>type</code>, которое называется <code>isserializable</code>.</p>

<p>вам нужно будет проверить все типы в графе сериализуемых объектов на предмет атрибута serializable. самый простой способ - попытаться сериализовать объект и поймать исключение. (но это не самое чистое решение). type.isserializable и проверка атрибута serializalbe не учитывают график.</p><p><em>образец</em></p><pre><code>[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); } } </code></pre>

<p>это старый вопрос, который может потребоваться обновить для .net 3.5+. type.isserializable может фактически возвращать false, если класс использует атрибут datacontract. вот фрагмент, который я использую, если он воняет, дайте мне знать :)</p><pre><code>public static bool isserializable(this object obj) { type t = obj.gettype(); return attribute.isdefined(t, typeof(datacontractattribute)) || t.isserializable || (obj is ixmlserializable) } </code></pre>

<p>используйте type.isserializable, как указали другие.</p><p>вероятно, не стоит пытаться отразить и проверить, все ли элементы в графе объектов являются сериализуемыми.</p><p>элемент может быть объявлен как сериализуемый тип, но фактически может быть создан как производный тип, который не сериализуем, как в следующем надуманном примере:</p><pre><code>[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 </code></pre><p>следовательно, даже если вы определите, что конкретный экземпляр вашего типа является сериализуемым, вы в целом не можете быть уверены, что это будет верно для всех экземпляров.</p>

<pre><code>attribute.isdefined(typeof (yourclass), typeof (serializableattribute)); </code></pre><p>наверное, подразумевает отражение под водой, но самый простой способ?</p>

<p>вот вариант 3.5, который делает его доступным для всех классов, использующих метод расширения.</p><pre><code>public static bool isserializable(this object obj) { if (obj is iserializable) return true; return attribute.isdefined(obj.gettype(), typeof(serializableattribute)); } </code></pre>

<p>я взял ответ на этот вопрос и ответ <a href="https://stackoverflow.com/questions/236599/how-to-unit-test-if-my-object-is-really-serializable/236698#236698">здесь</a> и изменил его, чтобы вы получили список типов, которые нельзя сериализовать. таким образом, вы можете легко узнать, какие из них пометить.</p><pre><code> 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)))); } </code></pre><p>и тогда ты называешь это ...</p><pre><code> list<string> nonserializabletypes = new list<string>(); nonserializabletypesofparenttype(atype, nonserializabletypes); </code></pre><p>при запуске nonserializabletypes будет иметь список. возможно, есть лучший способ сделать это, чем передать пустой список в рекурсивный метод. кто-нибудь поправит меня, если так.</p>

<p>мое решение, в vb.net:</p><p>для объектов:</p><pre><code>''' <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 </code></pre><p>для типов:</p><pre><code>''' <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 </code></pre>

<p>объект исключения может быть сериализуемым, но с использованием другого исключения, которого нет. это то, что я только что сделал с wcf system.servicemodel.faultexception: faultexception является сериализуемым, а exceptiondetail - нет!</p><p>поэтому я использую следующее:</p><pre><code>// 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); } </code></pre>