Are Arrays OK in Contracts?

I know its been a while, but I've been busy coding lately. That code will become public fairly soon, so I'll talk about it then. I'm still working on the promised Proxies and Adapters post, it will be coming, I promise. But in the meantime, the subject of my last post came up in practical terms at work the other day. One of the developers asked a seemingly innocent -- and presumably simple to answer -- question: Can I pass a byte array as a paramter in a contract, or do I have to use one of the collection contracts?

The answer, as it turns out is, unfortunately, "it depends." It depends on what you are doing with that array. I explained in the previous post that certain types can change behavior from reference to value depending on whether you pass them in AppDomain or cross-AppDomain. Any reference type that is *not* MarshalByRef but *is* serializable exhibits this idiosyncracy. And probably the most frequently used type in this category is System.Array.

So what it comes down to is this: are you OK with the recipient of the array getting a copy of the array, not a reference to the array: passing it cross-domain make Array into a value type. With byte array, in particular, this is most likely the intent. Byte arrays are typically used to move bags of bits around -- the recipient of the array would rarely change an element of the array and expect that change to be reflected in the caller. So for the particular case in question we decided that, yes, putting the byte array as a parameter in the contract *was* OK.

But you need to be careful. Many times, if not usually, if you are passing an array of objects, the opposite expectation would be true: in many scenarios I expect you to change the elements, or even fill them in. Of course in contracts object[] is strictly illegal, what you would consider passing instead is IContract[]. Even looking at that seems weird, don't you think? Instead, to get the desired behavior, you should pass the IArrayContract<> (or one of the other generic collection contracts) to get the desired behavior of a MarshalByRef array that can be altered by the callee and have the results show up in the original array.

So those are the two extremes: byte[] to IArrayContract<>. Everything in between, and in fact even these two, is a judgement call. Can you live with value type sematics with the array you are passing? Is that what the callee expects? Then its probably OK. But if you expect the callee to treat the array as a reference type, don't pass array.