views:

39

answers:

1

The ultimate goal is to specify contracts for a class that resides in an external assembly that I don't have control over (i.e. I cannot just add contracts to that class directly).

What I have tried so far:

  1. ContractClassFor attribute.
    Doesn't work, because the target class must point back to the contract class.

  2. Manually construct a contract reference assembly (i.e. MyAsm.Contracts.dll) by reverse-engineering the autogenerated ones.
    Doesn't work, because right after I compile it, the rewriter kicks in and conveniently strips off the ContractDeclarativeAssembly attribute, which makes the assembly unrecognizable by the tools as "contract reference assembly". And I cannot find a way to turn the rewriter off.

  3. Create a "fake" assembly with same name, version, strong name (if any) and other attributes as the target assembly, and put same-named classes with same-named methods in there. Then compile that assembly with "build contract reference" option turned on, then take the generated contract reference assembly and use it.
    This also didn't work for some reason, although I have no idea what that reason was exactly. The static checker simply ignores my smartypants-generated reference assembly, as if it didn't exist.

And one more thing, just in case it matters: the target assembly is compiled for .NET 2.0, and I cannot recompile it for 4.0.

Update

Writing a "wrapper" library with defined contracts is out of question.

For one, it's a lot of extra code to write. But even if you leave that aside, it may be a significant performance penalty: I would have to (potentially) create wrapper classes for every "legacy" type that is used as return type from my "legacy" methods. But even that is not the end of the story. Imagine that some methods may return references to base interfaces, and then the calling code might cast them to derived interfaces to see if the object supports more functionality. How do I wrap those? I would probably have to provide custom Cast<T>() methods on my wrapping classes, which will try to cast the underlying class/interface and return a wrapper for result if successful. In the end, my whole codebase will become so convoluted that it's probably not worth it anyway.

On the other hand, precisely this problem has already been successfully solved by the CC team itself: they do ship proper contract reference assemblies for mscorlib, System.Core and some other system assemblies, don't they? How did they manage to build them? If they can do it, then I don't see any reason why I shouldn't be able to pull off the same trick.

Oh, well, actually, I do see one reason: I don't know how to do it. :-) – Fyodor Soikin 18 secs ago edit

+1  A: 

A work-around could be to create a 'facade' layer between your code and the external assembly. This layer can hold all the contracts that you would apply on the external code.

If you do not want to change anything in the existing code, I'm afraid there's not much more you can do.

KoMet
Well, yes, that is basically what I'm doing right now. For one, it's a lot of extra code to write. But even if you leave that aside, it may be a significant performance penalty: I would have to (potentially) create wrapper classes for every "legacy" type that is used as return type from my "legacy" methods. But even that is not the end of the story. Imagine that some methods may return references to base interfaces, and then the calling code might cast them to derived interfaces to see if the object supports more functionality. How do I wrap those? Wrapping a whole library is a big endeavor.
Fyodor Soikin
On the other hand, precisely this problem has already been successfully solved by the CC team itself: they do ship proper contract reference assemblies for mscorlib, System.Core and some other system assemblies, don't they? How did they manage to build them? If they can do it, then I don't see any reason why I shouldn't be able to pull off the same trick. Oh, well, actually, I do see one reason: I don't know how to do it. :-)
Fyodor Soikin
Seeing that the Contract class is part of the BCL, I suppose they have access to the mscorlib code =)
KoMet