0

If I have a class (class P) which makes use of some other re-usable component (class C) (eg a state manager), then if that component needs to access some data within my top level class (P), then what choices do I have?

The key thing is that I dont want to expose this data to the outside world, just to within components I know and trust and use within P.

public static class Program
{
    private void Main()
    {
        var owner = new Owner();

        // I can call Foo()!!!
        ((IOwner)owner).Foo();
    }
}


public interface IOwner
{
    void Foo();
}

public class Owner : IOwner
{
    private Component m_component;

    public void SomeExternalAPI()
    {
        m_component = new Component(this);
        m_component.DoSomething();
    }

    void IOwner.Foo()
    {
        // do something
    }
}

public class Component
{
    private readonly IOwner m_owner;

    public Component(IOwner owner)
    {
        m_owner = owner;
    }

    public void DoSomething()
    {
        m_owner.Foo();
    }
}

I could use an interface on P, but this then exposes the data externally. I could use an explicit interface on P, but this can be cast and so also easily exposes the data.

If I could somehow impart "Friendship" upon the component (which I created, and ideally at the instance level!), and make IOwner a friend-only interface then, it would be secure.

I know this is impossible in C# at the moment.

It comes up quite often for me.

Has anyone got any solutions or suggestions?

fpdave100
  • 11
  • 5

2 Answers2

0

You can use the internal accessor on your interface and Component class.

internal interface IOwner
{
     void Foo();
}

internal class Component
{
     private readonly IOwner m_owner;

     public Component(IOwner owner)
     {
          m_owner = owner;
     }

     public void DoSomething()
     {
          m_owner.Foo();
     }
}

The Owner class would be public

public class Owner : IOwner
{
    private Component m_component;

    public void SomeExternalAPI()
    {
         m_component = new Component(this);
         m_component.DoSomething();
    }

    void IOwner.Foo()
    {
         // do something
    }
}

With this approach, you won't be able to access the interface nor the Component class from an external assembly

The client would only see the Owner class and its SomeExternalAPI() method.

var Owner = new Owner();
owner.SomeExternalAPI();
//owner.Foo() --> Won't compile!
//((IOwner)owner).Foo() --> Won't compile!
Matias Cicero
  • 25,439
  • 13
  • 82
  • 154
  • Hi, and thanks for your response. Unfortunately, use of internal is not flexible enough as often the component could be implemented in a different assembly, and/or I don't want code that uses the parent to have access to its internals even if it is in the same assembly. I guess what is needed would be friend, or a friend interface maybe rather than a full friend? – fpdave100 Aug 14 '14 at 16:08
  • Component could be a plugabble assembly in many cases. But your partial solution is the best I've found so far – fpdave100 Aug 15 '14 at 08:16
  • I'm sorry for my late response, @fpdave100. If that's the case, I'd recommend you read about **Friendly Assemblies at MSDN** ([Link here](http://msdn.microsoft.com/en-us/library/0tke9fxk.aspx)). Basically, it's just a **class attribute** that is able to make your class visible to **specific** assemblies – Matias Cicero Aug 15 '14 at 11:10
  • I managed to do it using a Proxy class which implemented a public interface IOwner, and created an internal interface IInternalOwner, which the Owner actually implemented. The proxy was given an instance of IInternalOwner, but implemented IOwner. The component then called methods on the proxy, which then delegated them straight thru to the actual owner via its internal interface. – fpdave100 Aug 15 '14 at 23:04
0

I think I've found a reasonable solution, altho its quite hard work and more code than I'd like

Use a proxy class, which implements the public IOwner interface, but which can then call into the actual owner using an internal IInternalOwner interface, which it was given on construction.

The proxy then acts like a token allowing the owner to be called by anyone it gives this token to. Its more code than I would like, and it would be nice if this was built into C# :-).

But, it works between assemblies (in fact I had 4 to test it!).

public class Owner : IInternalOwner
{
    private ITheComponent m_component;

    public void SomeExternalAPI()
    {
        var proxy = new Proxy(this);
        m_component = ClassFactory.ConstructTheComponent(proxy);
        m_component.DoSomething();
    }

    void IInternalOwner.Foo()
    {
        // do something
        Console.WriteLine("Owner.Foo was called");
    }

    private class Proxy : IOwner
    {
        private IInternalOwner m_owner;

        public Proxy(IInternalOwner owner)
        {
            m_owner = owner;
        }

        /// <summary>
        /// pass through for each method & property!
        /// </summary>
        public void Foo()
        {
            m_owner.Foo();
        }
    }


}

internal interface IInternalOwner
{
    void Foo();
}
fpdave100
  • 11
  • 5