Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Code contract rewrite failing with 'Could not resolve member reference'

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?

like image 248
WalderFrey Avatar asked Feb 12 '16 17:02

WalderFrey


1 Answers

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.

like image 83
Michał Komorowski Avatar answered Nov 18 '22 13:11

Michał Komorowski