views:

317

answers:

4

I've been trying to sign an assembly and getting this error:

'Utils.Connection' does not implement interface member 'Interfaces.IConnection.BugFactory()'. 'Utils.Connection.BugFactory()' cannot implement 'Interfaces.IConnection.BugFactory()' because it does not have the matching return type of 'ThirdPartyLibrary.BugFactory'.

That error looks like a dirty, dirty lie! In Utils.Connection, I have this method:

public new BugFactory BugFactory()

I don't think the new keyword is the problem because 1) removing it doesn't stop the error and 2) I'm having the same error with another class that implements IConnection that does not use the new keyword. Update: if I use override instead of new, I get this error:

'Utils.Connection.BugFactory()': cannot override because 'ThirdPartyLibrary.ConnectionClass.BugFactory' is not a function

This is because ThirdPartyLibrary.ConnectionClass.BugFactory is a property.

There is only one BugFactory class, so it isn't a problem of the interface requiring a different BugFactory return type than what the method returns. Even if I explicitly mark my method as returning ThirdPartyLibrary.BugFactory, I still get the error when I try to strong-name the Utils DLL.

Could this be the result of ThirdPartyLibrary being an old COM library that is not CLS-compliant? I have no control over this library. When I do not try to sign the Utils assembly, I do not get the interface error.

My big question is: how can I sign this assembly?

Edit: here's what IConnection has:

using ThirdPartyLibrary; // The only using statement
namespace Interfaces
{
   public interface IConnection
   {
       ...
       BugFactory BugFactory();
   }
}
+1  A: 

Namespace/version problems?

ThirdPartyLibrary.BugFactory might be a different type, if you have two different versions of the 3rd party assembly being referenced somehow: One during compile time and a different one when you sign/verify..

Benjamin Podszun
When I check the Reference properties on each project (`Connection` is in `Utils`, `IConnection` is in `Interfaces`), they both reference the same `ThirdPartyLibrary` (at least the "Identity" fields match).
Sarah Vessels
A: 

What does your IConnection interface look like? It seems like your ThirdPartyLibrary has a BugFactory object and you also have a BugFactory object either in your project or another reference. Did you try changing both the interface and the concrete type to explicity use ThirdPartyLibrary.BugFactory as the return type for that method?

Scott Anderson
Updated question to provide `IConnection` details. Being explicit about `ThirdPartyLibrary.BugFactory` in both the interface and the class implementing it didn't work. :(
Sarah Vessels
+3  A: 

I'm still suspicious of the new keyword for this error.

You say "I don't think the new keyword is the problem because 1) removing it doesn't stop the error", but you must bear in mind that if your method hides a base method, the compiler will add a new, even if you don't specify it, unless you explicity specify override instead.

All the explicit new does is to prevent a compiler warning (not an error).

Is there really a method to hide or override at all?

What happens if you specify virtual instead of new on this method. Does it compile? Does it error with "no suitable method found to override?"

[Edit in response to your comment]

I get this error: "'Utils.Connection.BugFactory()': cannot override because 'ThirdPartyLibrary.ConnectionClass.BugFactory' is not a function." The original ThirdPartyLibrary.ConnectionClass.BugFactory is a property.

I suspect this may be the issue. You are overriding a property with a method.

By using the new keyword, you are hiding the old property to anyone that has a reference to your derived class.

By contrast, anyone that has a reference cast as the superclass (the one you are inheriting from), they will see the old property, and not your new method.

Can you give some more code of the superclass (or interface) together with the derived class?

[Edit in response to your comment]

I'm trying to change the interface to have BugFactory be a property instead of a method

The trouble with new is that it seems like a bit of magic, that can let you change argument types and return types, but it is really pure evil.

Instead of changing the types for all consumers of the code, it only does it for consumers that are cast as the overriding new type. This gets you in the horrible position where two consumers to the same instance will see different signatures depending on how they are cast.

See if you can identify the consuming code that is complaining, and have a think around whether more of your code needs to change to support the type changes. Also, is there the possibility that you are trying to do something that is "a bit of a nasty hack"?

Rob Levine
I get this error: "'Utils.Connection.BugFactory()': cannot override because 'ThirdPartyLibrary.ConnectionClass.BugFactory' is not a function." The original `ThirdPartyLibrary.ConnectionClass.BugFactory` is a property.
Sarah Vessels
`public virtual BugFactory BugFactory()` in `Utils.Connection` compiles fine. `public new virtual BugFactory BugFactory()` also compiles fine and gets rid of the compiler warning about hiding.
Sarah Vessels
I'm trying to change the interface to have `BugFactory` be a property instead of a method, to match the original `BugFactory` in `ThirdPartyLibrary`.
Sarah Vessels
When the compilation fails with your original error (when you use new), who is the consumer of the code who is complaining about the mismatch? Does the consumer have a reference cast to the interface or the concrete type?
Rob Levine
I don't know that there is a real consumer. The interface error just points to the line in `Connection` where the class is declared.
Sarah Vessels
I really think you're going down the wrong road with this solution. How does this explain why it compiles fine when not trying to sign?
Nick
@Nick - I may not be right, of course. My aim was to understand the compiler error in the hope it shed light on what the real problem was, and why. Something along the lines that strong naming an assembly causes the linker to be very picky about which assemblies it links to. Could this actually be causing a dll to suddenly start compiling against a different version of the dll? I was going to try and have a play with this last night, but ran out of time. (Specific version in GAC, another version side-by-side in dir, etc) OP - did you get this sorted?
Rob Levine
@Rob Levine - I really have a strong feeling this has to do with the fact that the COM dll needs a PIA that can be strong named as I mentioned in my answer below. I'm really curious if Sarah tried that.
Nick
+1  A: 

It sounds like you are simply referencing the COM library through the Add Reference dialog. You should probably create a Primary Interop Assembly for the COM library which can be signed. One of the caveats of signing an assembly is that all the assemblies it references must also be signed.

You would normally use the SDK program TlbImp:

TlbImp yourcomlibrary.tlb /primary /keyfile:yourkeyfile.snk /out:yourcomlibrary.dll

Nick