Note that this might be a duplicate of this question, I'm not entirely sure.
My problem is that I have a class library project which has a reference to a third-party type library (COM). I want to put contracts into the methods in the class library, like so:
public class foo
{
public static int divide(TypeFromTypeLib tftl, int a, int b)
{
Contract.Requires<ArgumentException>(b != 0);
return a / b;
}
}
And then have a client project make use of this method, e.g.
var n = foo.divide(null, 4, 2);
But I'd also like the client project also use contracts in some of its methods. So, I set the Code Contracts properties on both projects to 'Perform Runtime Contract Checking' (without which you get the runtime assert telling you that it needs this setting).
Now, when I then try to compile the client, I get the following error:
Could not resolve member reference: my_class_lib.foo::divide.
ccrewrite : error : Rewrite aborted due to metadata errors.
Which seems unavoidable - any time a method is called which has a type from the third party type library this happens. Remove the type from the method's signature and it's fine.
Can anyone explain why this happens? Is this a clue that the structure of my code is fundamentally flawed (if so, why?), or is it a quirk of code contracts? Is there a recommended fix for this problem?
To be honest I don't know why ccrewrite has a problem with interop types but I can give you 3 workarounds:
Solution 1
This one is the simplest:
You have to do that for both projects. The drawback of this solution is that after a build you will get an additional interop assembly in the bin folder.
Solution 2
Another solution might be to remove types from a third-party type library from a public interface i.e.:
public class foo
{
public static int divide(int a, int b)
{
return divide(null, a, b);
}
private static int divide(TypeFromTypeLib tftl, int a, int b)
{
Contract.Requires<ArgumentException>(b != 0);
return a / b;
}
}
Of course you can do that only if you do not need to use TypeFromTypeLib
in your client.
Solution 3
If you need to use TypeFromTypeLib
in your client you may write a wrapper for this class i.e.:
public class MyTypeFromTypeLib
{
//...
}
public class foo
{
public static int divide(MyTypeFromTypeLib mytftl, int a, int b)
{
var tftl = new TypeFromTypeLib();
//Map MyTypeFromTypeLib to TypeFromTypeLib
//...
return divide(tftl , a, b);
}
private static int divide(TypeFromTypeLib tftl, int a, int b)
{
Contract.Requires<ArgumentException>(b != 0);
return a / b;
}
}
However, this solution is cumbersome because additional classes are needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With