views:

83

answers:

5

The question of why there are no friends in C# has been extensively discussed.

I have the following design problem.

I have two classes TradingSystem and Order. TradingSystem class has only one public function AddOrder(Order ord). Clients are allowed to call only this function. All other logic must be hidden. Order class is listening to market events and must call other other function of TradingSystem ExecuteOrder, so I have to make it public as well. Doing that I will allow clients of Trading system to call this function and I don't want that.

UPDATE Order class and TradingSystem are living in separate assemblies. Order class is base class and many other classes can be derived.

    class TradingSystem
    {
     // Trading system stores list of orders
      List<Order> _orders;

     // this function is made public so that Order class can call it when need
     // but other class must not call it
      public ExecuteOrder(Order ord)
    {
 // some logic
    }  
      // this function is made public for external clients
      public AddOrder(OrderRequest ordreq)
     {
       // omitted code
       // create order and pass it this 
       order.OnOrderAdded(this);
     }
    }

    class Order
    {
      // reference to TradingSystem class is stored to call it methods
      TradingSystem _ts;

      public void OnOrderAdded(TradingSystem ts)
    {
       _ts = ts;
    }

   // this function is called on timer
    void OnMarketEvent()
    {
       if(/*some logic*/)
      _ts.ExecuteOrder()
    }  
    }
+1  A: 

Assuming all clients are outside your assembly, you can declare ExecuteOrder as internal.

Otherwise you can declare an interface that exposes the one method and provide that interface to clients instead of the object. In fact, if the API is inherently singular, you could supply the client with nothing more than an Action<OrderRequest>.

Marcelo Cantos
+2  A: 

Change AddOrder and ExecuteOrder to be internal, and have two proxying classes in the same assembly, each of which can be created with a TradingSystem and delegates one of the methods.

Then you give anything that needs to call AddOrder a proxy which can do just that, and anything which needs to call ExecuteOrder a proxy which can do just that.

You could potentially leave both methods public and just make TradingSystem implement two interfaces - but that would allow clients to just cast to the concrete type and make the call anyway.

Access modifiers shouldn't generally be used as a layer of security, by the way - if this is a genuine trading system (rather than just an example of the sort of separation you want) then I'd expect the security to be implemented rather differently.

Jon Skeet
@Jon: Wouldn't declaring `TradingSystem` internal prevent the clients from casting?
Vlad
@Vlad: It would prevent casting to TradingSystem - but it wouldn't prevent casting to the other interface (assuming there were two interfaces).
Jon Skeet
+1  A: 

If both classes are in same assembly and the clients are not you can use internal keyword.

The internal keyword is an access modifier for types and type members. Internal types or members are accessible only within files in the same assembly.

If they are not you can still use the internal keyword but you must declare that the internals of the assembly declaring TradingSystem are visible to the assembly containing Order. For this you can use the attribute InternalsVisisibleTo.

InternalsVisibleToAttribute Class

You should note that clients can still call these methods via reflection, even the private ones.

João Angelo
Order and TradingSystem belong to different assemblies
Captain Comic
@Captain Comic, the second option is still feasible.
João Angelo
+2  A: 

You can make two interfaces for TradingSystem, one for clients and one for Orders. Your clients get your first interface, the Orders get the second (instead of TradingSystem itself).

public interface I1
{
    void AddOrder(Order ord);
}

public interface I2
{
    void ExecuteOrder(Order ord);
}

internal class TradingSystem: I1, I2
{
    ...
Vlad
+2  A: 

The C# keyword internal is the equivalent of VB's Friend. Combine this with the InternalsVisisibleToAttribute and you should be home safe in this example.

MEMark