7

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?

Community
  • 1
  • 1
WalderFrey
  • 575
  • 2
  • 17
  • I am getting this error from ccrewrite, from methods in a 1st party library that have embedded interop types in their signature. – JamesFaix Feb 29 '16 at 17:42
  • I had my project open in VS2015 and switched to VS2013 and the issue went away. The Roslyn compiler seems to treat embedded interop types differently than the old compiler, but I can't find any documentation or conversation about it. Possibly related: http://stackoverflow.com/questions/35641972/why-does-visual-studio-2015-throw-more-cs1769-compiler-errors-than-vs2013 – JamesFaix Mar 01 '16 at 00:00
  • What version of code contracts do you have installed? Up until the release of v.1.10.10126.2-rc1 on Jan 26, 2016 I've never got runtime checking in code contracts working in Visual Studio 2015. This version is the first major community-driven release of code contracts and addresses a lot of pending issues. It can be downloaded from: https://github.com/Microsoft/CodeContracts/releases. I have it installed and runtime checking now works for me again. – Ɖiamond ǤeezeƦ Mar 01 '16 at 12:21
  • I know that the generic and regular versions of `Contract.Requires` are treated differently by `ccrewrite` in that the later can be included in the code even if you do not execute `ccrewrite`. Have you tried replacing `Contract.Requires(b != 0);` with `Contract.Requires(b != 0);` ? – Igor Mar 07 '16 at 16:39

1 Answers1

3

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:

  • Go to list of references for a project.
  • Find third-party type library.
  • Right click.
  • From the context menu select Properties.
  • Change Embed Interop Types from True to False.

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.

Michał Komorowski
  • 6,198
  • 1
  • 20
  • 24