tags:

views:

58

answers:

2

I have two assemblies: A and B. A has InternalsVisibleTo set for B. I would like to make calls from A to get information that can only be known by a type defined in B in a way that keeps things internal. I can do this using an internal interface defined in A and implemented explicitly in B.

Assembly A

  internal interface IHasData
  {
    Data GetData();
  }

  class ClassA 
  {
    DoSomething(IHasData);
  }

Assembly B

  public abstract class ClassB : IHasData
  {
    Data IHasData.GetData() { /** do something internal **/ }
  }

The trouble comes when someone references assembly B and derives from ClassB - they get the error: "The type 'AssemblyA.IHasData' is defined in an assembly that is not referenced" even though that type should be invisible to them. If I look at the public type definition I see what I expect - ClassB with no interfaces implemented.

Why do I get this error? All of the implementation is in assembly B. I could use IHasData internally in ClassB and that wouldn't require assembly A to be referenced. Can someone help me understand what is going on?

A: 

ClassB is publicly visible outside of its assembly, so all of its base types -- classes and interfaces -- must also be publicly visible. Something that derives from ClassB in a different assembly will not be able to see IHasData unless you provide an InternalsVisibleTo for that assembly as well.

ClassB also implements IHasData explicitly, which means that the implementation is public by default.

Niall C.
+2  A: 

It's an interesting find, but it looks like the rules of referencing your references' dependencies when those dependencies are exposed by the reference still apply for explicit interface implementations. I've answered a few questions about this before here.

A better solution would be to favour composition over inheritance and define an implementation of IHasData in an internal class that Assembly B doesn't expose. Something along these lines:

  public abstract class ClassB
  {
    class HasData : IHasData
    {
      HasData(ClassB b) {m_b = b;}
      Data IHasData.GetData() { m_b.GetData(); }
    }

    private readonly HasData m_hasData;

    public ClassB() {
      m_hasData = new HasData(this);
    }

    internal Data GetData() { 
      /** do something internal **/ 
    }
  }
Igor Zevaka
+1 for a solid approach. I would consider adding an internal, implicit operator to convert an instance of `ClassB` to an `IHasData` as well. Then `ClassB` can still be used internally *as though* it were an `IHasData`.
Mark Rushakoff
Thanks. Yeah, that would totally work in a sneaky implicit operator trickery way. In this implementation though, `HasData`'s job is to delegate to ClassB, so those methods might be available anyway. My preferred approach would be to contain the `IHasData` logic as much as possible in `HasData` class and limit its dependency on `ClassB`.
Igor Zevaka
The issue with this approach is that it is more difficult for assembly A to consume it - though this can be worked around as Mark suggested. Do you know if there is a reason for this restriction?
dmo
Nope, you'd need a C# compiler guru to explain this one :))
Igor Zevaka