4

I know it sounds stupid but I am just being curious. My lecturer asked this question and we were clueless. :D

Gayan Jayasingha
  • 752
  • 2
  • 17
  • 33
  • 1
    Because it is counterintuitive. Serializable implies a 'MarshalByValueObject', and not a remote reference for what `MarshalByRefObject` is used. It would probably confuse the hell out of the remoting system ;p (btw, not a stupid question) – leppie Apr 23 '14 at 09:10
  • @Sergey I already saw that question but that was for two different classes. What I meant was for a single class. There is a similar question posted here [link](http://stackoverflow.com/questions/8799202/what-happens-when-an-object-derives-from-marshalbyrefobject-and-is-also-marked?rq=1) but that answer is confusing. – Gayan Jayasingha Apr 23 '14 at 09:15
  • @leppie no, I disagree; I don't think it implies that at all – Marc Gravell Apr 23 '14 at 09:34
  • 1
    Your lecturer is wrong. – Marc Gravell Apr 23 '14 at 09:36

2 Answers2

6

Your lecturer is incorrect.

foreach(var type in typeof(Uri).Assembly.GetTypes())
{
    if (type.IsAbstract) continue;
    if (!Attribute.IsDefined(type, typeof(SerializableAttribute))) continue;
    if (!typeof(MarshalByRefObject).IsAssignableFrom(type)) continue;
    Console.WriteLine(type.FullName);
}

shows (and note that I'm only looking at a single assembly here):

System.Media.SoundPlayer
System.Net.FileWebRequest
System.Net.FileWebResponse
System.Net.HttpWebRequest
System.Net.HttpWebResponse
System.Diagnostics.EventLogEntry

and sure enough, http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.aspx shows:

[SerializableAttribute]
public class HttpWebRequest : WebRequest, 
    ISerializable

noting also:

[SerializableAttribute]
public abstract class WebRequest : MarshalByRefObject, 
    ISerializable

For mscorlib (typeof(object)), we get:

System.IO.Stream+SyncStream
System.IO.DirectoryInfo
System.IO.FileInfo
System.IO.MemoryStream
System.IO.TextReader+SyncTextReader
System.IO.StreamReader
System.IO.TextWriter+SyncTextWriter
System.IO.StreamWriter
System.IO.StringReader
System.IO.StringWriter
System.IO.Stream+NullStream
System.IO.TextReader+NullTextReader
System.IO.TextWriter+NullTextWriter

That's enough concrete counter-examples, I suspect.

I suspect that your lecturer is only thinking of remoting, i.e. where we expect something to either be remoted as a proxy/stub pair, or by serialization. However, this is invalid.

  • [Serializable] is also used purely for serialization purposes outside of remoting
  • remotable classes can be (and usually are) used separately-to and independently-of remoting
  • remoting is dead; tell them to stop teaching remoting, please

Or alternatively, consider:

When remoting is used, MarshalByRefObject indicates that the object should be remoted by proxy/stub - otherwise, the object needs to be serializable, so [Serializable] is required. However, the reverse is not true: [Serializable] does not mean "marshal by value" (simply: the lack of MarshalByRefObject is what means "marshal by value"). A type can be both serializable and remoted by proxy/stub. There is no conflict here.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • If remoting is dead, then how do you do cross appdomain object references? Ups, it is not - remoting is still used extremely widely in standard scenarios like this (and there are a great many uses to put stuff in appdomains, to be able to totally unload it). – TomTom Apr 23 '14 at 09:39
  • A small follow-up q. Say, I have a `List` of MBR object, which I serialize as XML and then de-serialize inside a different domain. I expect I'd get a copy of the list which contains proxies to the original MBR objects, all OK. However, what if I restart the app (the MBR objects are gone), the de-serialize the XML graph? Am I gonna get a runtime error, or copies of the original MBR objects? – noseratio Apr 23 '14 at 09:42
  • Why not use `Type.IsSerializable`? – leppie Apr 23 '14 at 09:46
  • @TomTom yes, I will grant you that: remoting is still viable in AppDoman scenarios (although other approaches will work too). I shudder when people are using remoting as a inter-process / inter-machine communication device, though – Marc Gravell Apr 23 '14 at 09:46
  • @leppie because not everyone knows that `[Serializable]` has special handling (the compiler doesn't even add the `SerializableAttribute`, really), and I wanted it to be as obvious as possible. But yes, `.IsSerializable` is much more efficient here (no attribute spoofing required) – Marc Gravell Apr 23 '14 at 09:47
  • @MarcGravell: I shudder when people use WCF for simple IPC ;p – leppie Apr 23 '14 at 09:47
  • @leppie agreed, but then: I'm a raw socket kinda person ;p – Marc Gravell Apr 23 '14 at 09:47
  • @Noseratio why would you expect proxies to the original MBR records? Since you are serializing to XML, I would not expect that *at all*. – Marc Gravell Apr 23 '14 at 09:48
  • @MarcGravell: It is much harder to blow your leg off with WCF though. :) – leppie Apr 23 '14 at 09:49
  • 1
    @leppie only because the `ILegBlowOffChannelProxyFactory` is poorly documented, and can only be accessed at a silly point in the WCF pipe. – Marc Gravell Apr 23 '14 at 09:50
  • @Noseratio: You can use serialization surrogates for that (I do the same in IronScheme, to intern symbols and boolean values on deserialization). – leppie Apr 23 '14 at 09:50
  • @MarcGravell, I never tried that, but I expect there has to be a way to persist a reference to an MBR object as a unique string, for transferring it over the wire. In DCOM, I used `OBJREF` moniker for that. I'm going to check how it works with .NET remoting. – noseratio Apr 23 '14 at 09:54
  • 1
    Searching `mscorlib.dll` (use `typeof(object).Assembly`) finds more classes like that. – Jeppe Stig Nielsen Apr 23 '14 at 09:57
  • @JeppeStigNielsen added (removing all `abstract` types, for clarity) – Marc Gravell Apr 23 '14 at 10:11
  • Wow! What an explanation! So simply put, if I use both [Serializable] and inherit from MarshalByRefObject at the same time OR only inherit from MarshalByRefObject then a reference of that object is passed always. And if I want to get a copy of that object then I have to mark it as [Serializable] ONLY. Is that right? – Gayan Jayasingha Apr 23 '14 at 10:37
  • 1
    @gayanjayasingha essentially, yes – Marc Gravell Apr 23 '14 at 10:55
0

MarshalByRefObject is already marked as Serializable, so this may seem a bit weird.

However, this is more about logically using the tools you have. Since MarshalByRefObjects are actually accessed using proxies, they don't have a local state to serialize when you're using the proxy. That's the whole point of MarshalByRefObject. When you're using serialization, you're transferring (or saving) the state - when marshalling by reference, you're only transferring a reference to the object. So serialization is a copy, while marshal by ref is still refering to the same object, even accross application domain boundaries.

Now, as far as I know, there's actually no check to make sure the object isn't serializable - however, in practice, when it's used from outside of its application domain, there really isn't anything to serialize.

Luaan
  • 62,244
  • 7
  • 97
  • 116
  • It is marked `Serializable` in a special way to carry to reference to the remote proxy. – leppie Apr 23 '14 at 09:13
  • @leppie Yeah, that's what I thought. That's also the only information the proxy class really has, after all. – Luaan Apr 23 '14 at 09:16
  • Remark: The `SerializableAttribute` class has an `AttributeUsageAttribute` that sets `Inherited = false`, so it would seem relevant to apply `[Serializable]` again to derived classes. – Jeppe Stig Nielsen Apr 23 '14 at 09:46
  • @JeppeStigNielsen True, I've noticed that too. The thing is, you don't really want to serialize the `MarshalByRefObject`, because unless it's in your domain, it's not really there - you're only interacting with its proxy. However, if you want to allow serialization, you're better off using `ISerializable`, which allows you to do the serialization in the proper domain, and send just the results to the caller. I expect that using `[Serializable]` would either return bogus data, or only return the proxy's data (which is already in `MarshalByRefObject`. – Luaan Apr 23 '14 at 10:58