Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The type 'T' is not compatible with the type 'T'

I have two libraries written in C# that I'd like to use in an F# application. Both libraries use the same type, however, I am unable to convince F#'s type checker of this fact.

Here's a simple example using the Office interop types. F# seems particularly sensitive to these type issues. Casting on the F# side does not seem to help the situation. All three projects have a reference to the same assembly ("Microsoft.Office.Interop.Excel" version 14.0.0.0).

In project "Project1" (a C# project):

namespace Project1
{
    public class Class1
    {
        public static Microsoft.Office.Interop.Excel.Application GetApp()
        {
            return new Microsoft.Office.Interop.Excel.Application();
        }
    }
}

In project "Project2" (a C# project):

namespace Project2
{
    public class Class2
    {
        Microsoft.Office.Interop.Excel.Application _app;

        public Class2(Microsoft.Office.Interop.Excel.Application app)
        {
            _app = app;
        }
    }
}

In project "TestApp" (an F# project):

[<EntryPoint>]
let main argv = 
    let c2 = Project2.Class2(Project1.Class1.GetApp())
    0 

Any hints?

Edit:

Changing the call to Class2's constructor with the following dynamic cast solves the problem:

let c2 = Project2.Class2(Project1.Class1.GetApp() :?> Microsoft.Office.Interop.Excel.Application)

However, this is unsatisfying, since it is 1) dynamic, and 2) I still don't understand why the original type check failed.

like image 256
Dan Barowy Avatar asked Mar 10 '14 16:03

Dan Barowy


1 Answers

COM interop. When you reference a COM assembly it will actually generate a COM interop assembly to marshal between .NET and COM. If you have two assemblies both referencing the same COM assembly you may actually have two identically generated interop assemblies.

One solution, and frankly better design in general, would be to create interfaces in one of the two assemblies (or a shared 3rd assembly) which expose the features you want to make public and instead of using or consuming COM Types use these interfaces instead.

namespace Project1
{
    public interface IApplication
    {
        // application members here...
    }

    public class Class1
    {
        public static IApplication GetApp()
        {
            return new ExcelApplication(new Microsoft.Office.Interop.Excel.Application());
        }

        private class ExcelApplication : IApplication
        {
            public ExcelApplication(Microsoft.Office.Interop.Excel.Application app)
            {
                 this.app = app;
            }

            // implement IApplication here...
        }
    }
}
like image 189
justin.m.chase Avatar answered Nov 09 '22 22:11

justin.m.chase