C# friend equivalent solution, does this still break encapsulation?

  • (2 Pages)
  • +
  • 1
  • 2

18 Replies - 18351 Views - Last Post: 19 March 2013 - 08:48 PM Rate Topic: -----

#1 Muuski   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 18-March 13

C# friend equivalent solution, does this still break encapsulation?

Posted 18 March 2013 - 04:19 PM

I was working on a problem that involved two classes that are very similar to each other, but not enough to warrant mutual inheritance between them. I ran into an issue that could be conveniently solved if one of the classes had access to private members of the other, but decided instead that we should utilize a "friend" class to both classes who could mediate the interaction between them.

In the following example; FooData and BarData are the two similar classes that need to interact privately with each other. I decided to make them both inherit from Data and expose it's virtual protected interface to an internal class named DataProcessor, which is the "freind" class to FooData and BarData. An additional class named OutSider is present to illustrate that DataProcessor enjoys special access.

    public class Data{
        virtual protected void FooAccess() { }
        virtual protected void BarAccess() { }

        private class DataProcessor{
            public void Process(FooData foo, BarData bar){
                foo.FooAccess();
                bar.BarAccess();

                // This doesn't make sense conceptually, but can still happen.
                foo.BarAccess();
            }
        }
    }

    public class FooData : Data{
        protected override void FooAccess(){
            // Do some Foodoo.
        }
    }
    public class BarData : Data{
        protected override void BarAccess(){
            // Do the bar exam.
        }
    }

    public class OutSider{
        public void AccessData(FooData foo, BarData bar){
            // This will cause a compiler error.
            foo.FooAccess();
            bar.BarAccess();
        }
    }



I came up with this idea while reading Peretz.Net's Using Friends with C#, or should I say Bully. The problem I had with that solution was that you would not know which classes "bully" which and with my solution I believe it's more clear what's going on.

My question is; Does this necessarily break encapsulation? Is this a known solution/pattern with a name? Are there any improvements to this pattern that could be made?

I appreciate any discussion on these points and any suggestions.

Thank you.

Is This A Good Question/Topic? 0
  • +

Replies To: C# friend equivalent solution, does this still break encapsulation?

#2 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7360
  • View blog
  • Posts: 24,848
  • Joined: 05-May 12

Re: C# friend equivalent solution, does this still break encapsulation?

Posted 18 March 2013 - 06:16 PM

So, let me see if I understand this correctly. Let's say I have classes:
public class FloatPoint
{
    public float X { get; private set; }
    public float Y { get; private set; }
}

public class DoublePoint
{
    public double X { get; private set; }
    public double Y { get; private set; }
}



And your objective is to allow DoublePoint to be able to set values inside a FloatPoint, and vice versa?

Anyway, I usually am very skeptical about needing "friend" access. To me it means that I made a serious mistake early in my design phase, and I'm either to lazy, or my boss is too risk averse to do a refactoring of the code to fix it The Right WayTM.
Was This Post Helpful? 0
  • +
  • -

#3 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7507
  • View blog
  • Posts: 15,558
  • Joined: 16-October 07

Re: C# friend equivalent solution, does this still break encapsulation?

Posted 18 March 2013 - 06:26 PM

There's never really a NEED for friends. Even in C++, its use is often dubious. Some even put it in the goto bucket of language features.

Unfortunately, your foobar code doesn't give any real idea of what you're after or why you'd want to do it.

In C# you actually have the best of Java combined with a blatant disregard for Java's OO strictness. Modern C# has more than a little functional language creep.

You could reasonably just chuck delegates around. Maybe just interfaces? Without meaningful code, an actual problem, it's impossible to offer a solution.
Was This Post Helpful? 0
  • +
  • -

#4 Momerath   User is offline

  • D.I.C Lover
  • member icon

Reputation: 1021
  • View blog
  • Posts: 2,463
  • Joined: 04-October 09

Re: C# friend equivalent solution, does this still break encapsulation?

Posted 18 March 2013 - 07:40 PM

If one needs access to the others private methods, and their interaction is private (as you stated), why not just nest the classes?
Was This Post Helpful? 0
  • +
  • -

#5 AdamSpeight2008   User is offline

  • MrCupOfT
  • member icon

Reputation: 2298
  • View blog
  • Posts: 9,535
  • Joined: 29-May 08

Re: C# friend equivalent solution, does this still break encapsulation?

Posted 18 March 2013 - 07:50 PM

If you need to access another private method(s), then the problem is with your design.

This post has been edited by AdamSpeight2008: 18 March 2013 - 07:59 PM

Was This Post Helpful? 0
  • +
  • -

#6 Momerath   User is offline

  • D.I.C Lover
  • member icon

Reputation: 1021
  • View blog
  • Posts: 2,463
  • Joined: 04-October 09

Re: C# friend equivalent solution, does this still break encapsulation?

Posted 18 March 2013 - 08:24 PM

Not always, Adam. Take a look at the collection classes and how they implement IEnumerable<T> with nested classes.
Was This Post Helpful? 0
  • +
  • -

#7 AdamSpeight2008   User is offline

  • MrCupOfT
  • member icon

Reputation: 2298
  • View blog
  • Posts: 9,535
  • Joined: 29-May 08

Re: C# friend equivalent solution, does this still break encapsulation?

Posted 18 March 2013 - 08:52 PM

The source collection is based in as a parameter of the constructor for that collections Enumerator, they still uses public methods on the source collections. No Private members / methods are accessed.
Primarily the Indexer.

This post has been edited by AdamSpeight2008: 18 March 2013 - 08:53 PM

Was This Post Helpful? 0
  • +
  • -

#8 Muuski   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 18-March 13

Re: C# friend equivalent solution, does this still break encapsulation?

Posted 18 March 2013 - 10:17 PM

I tried editing the example code because I've gone in a direction more like a template method, but haven't found the edit button for this forum . . . did D.I.C hide it?

Here's some more details about how we're going to access
    public class Data{
        virtual protected void FooAccess() { throw new NotImplementedException(); }
        virtual protected void BarAccess() { throw new NotImplementedException(); }

        protected void Process(FooData foo, BarData bar)
        {
            foo.FooAccess(bar);
            bar.BarAccess(foo);
        }
    }

    public class FooData : Data{
        protected override void FooAccess(FooData foo){
            // Do some Foodoo.
        }

        public void DoAccess(BarData bar){
            Process(this, bar);
        }
    }
    public class BarData : Data{
        protected override void BarAccess(FooData foo){
            // Do the bar exam.
        }

        public void DoAccess(FooData foo){
            Process(foo, this);
        }
    }



Basically what's going on is that neither of the Data classes are actually accessing private/protected methods themselves, we just want both of them to have references to each other so they can access their public interface. The issue is that the Access function of both classes must be called once and only once for each Process, and the process can be started by either calling Foo or Bar's DoAccess.

What we're trying to avoid is:
Foo receives Bar, and passes itself to Bar
Bar receive Foo, and passes itself to Foo
Repeat, repeat, repeat.

Instead we have a public interface for receiving references. We then pass ourselves and the reference to the base class Process() to have our protected functions called on both instances once. Whether you start with a Foo and pass a Bar or vice versa, it doesn't matter because they both call on the same inner process and the protected Access functions only get called once.

Honestly this thread is kinda moot because once you remove the nested class. . .this becomes day-to-day inheritance, and the only reason I had nested classes is because that article reminded me of them :P/>
Was This Post Helpful? 0
  • +
  • -

#9 Michael26   User is offline

  • Futurama: Insert funny joke here
  • member icon

Reputation: 414
  • View blog
  • Posts: 1,664
  • Joined: 08-April 09

Re: C# friend equivalent solution, does this still break encapsulation?

Posted 19 March 2013 - 01:53 AM

Quote

I tried editing the example code because I've gone in a direction more like a template method, but haven't found the edit button for this forum . . . did D.I.C hide it?


No they didn't hide the edit button, you just need certain amount of posts before you get the edit option(I see you only have 2 posts).
Was This Post Helpful? 0
  • +
  • -

#10 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7507
  • View blog
  • Posts: 15,558
  • Joined: 16-October 07

Re: C# friend equivalent solution, does this still break encapsulation?

Posted 19 March 2013 - 04:04 AM

Now the code doesn't even make syntactic sense. Again, a real world example. An actual situation where this is even remotely useful. The logic wall you hit that makes this seem like a solution. What problem are you trying so solve?

Given what you have:
interface IFooData { }

interface IFoo {
	void FooAccess(IFooData foo);
	IFooData FooData { get; }
}

interface IBarData { }

interface IBar {
	void BarAccess(IBarData bar);
	IBarData BarData { get; }
}

interface IFooBar : IFoo, IBar {
}

class Data {
	public void Process(IFooBar foo, IFooBar bar) {
		foo.FooAccess(bar.FooData);
		bar.BarAccess(foo.BarData);
	}
}


Was This Post Helpful? 0
  • +
  • -

#11 Momerath   User is offline

  • D.I.C Lover
  • member icon

Reputation: 1021
  • View blog
  • Posts: 2,463
  • Joined: 04-October 09

Re: C# friend equivalent solution, does this still break encapsulation?

Posted 19 March 2013 - 06:26 AM

View PostAdamSpeight2008, on 18 March 2013 - 07:52 PM, said:

The source collection is based in as a parameter of the constructor for that collections Enumerator, they still uses public methods on the source collections. No Private members / methods are accessed.


From Queue<T>.Enumerator (nested class in Queue<T>
public bool MoveNext() {
    if (this._version != this._q._version) {
        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
    }
    if (this._index == -2) {
        return false;
    }
    this._index++;
    if (this._index == this._q._size) {
        this._index = -2;
        this._currentElement = default(T);
        return false;
    }
    this._currentElement = this._q.GetElement(this._index);
    return true;
}


both this._q._version and this._q._size are private in Queue<T>
Was This Post Helpful? 1
  • +
  • -

#12 Muuski   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 18-March 13

Re: C# friend equivalent solution, does this still break encapsulation?

Posted 19 March 2013 - 12:15 PM

View Postbaavgai, on 19 March 2013 - 04:04 AM, said:

interface IFooData { }

interface IFoo {
	void FooAccess(IFooData foo);
	IFooData FooData { get; }
}

interface IBarData { }

interface IBar {
	void BarAccess(IBarData bar);
	IBarData BarData { get; }
}

interface IFooBar : IFoo, IBar {
}

class Data {
	public void Process(IFooBar foo, IFooBar bar) {
		foo.FooAccess(bar.FooData);
		bar.BarAccess(foo.BarData);
	}
}






If I'm not mistaken, all of the methods in that code are public. Clients could accidentally call FooAccess themselves. . . not knowing that they also need to call BarAccess as well.

That's why we need FooAccess and BarAccess to be less than public and yet can be called from some process method started in either Foo or Bar. I don't really see why it's so important to understand what these classes represent physically. We have two classes that reference each other...Probably begging for a mediator class between them, yes, but does it matter if they represent bank accounts or Quantum particles? Perhaps not.

View Postbaavgai, on 18 March 2013 - 06:26 PM, said:

You could reasonably just chuck delegates around. Maybe just interfaces?


Do you mean something like:

    class DataProcess{
        public static void Process(ExposedFoo foo, ExposedBar bar){
            foo.CallPrivates(bar);
            bar.CallPrivates(foo);
        }
    }

    class FooData{
        protected void FooAccess(BarData bar){
            // Do some Foodoo
        }
        public void StartProcess(BarData bar) { DataProcess.Process((ExposedFoo)this, (ExposedBar)bar); }
    }

    class BarData{
        protected void BarAccess(FooData foo){
            // Do the bar exam
        }
        public void StartProcess(FooData foo ) { DataProcess.Process((ExposedFoo)foo, (ExposedBar)this); }
    }

    abstract class ExposedFoo : FooData{
        public void CallPrivates(BarData bar) { FooAccess(bar); }
    }

    abstract class ExposedBar : BarData{
        public void CallPrivates(FooData foo) { BarAccess(foo); } 
    }



I find this Enumerator discussion irrelevant to the main track of discussion.
Was This Post Helpful? 0
  • +
  • -

#13 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7360
  • View blog
  • Posts: 24,848
  • Joined: 05-May 12

Re: C# friend equivalent solution, does this still break encapsulation?

Posted 19 March 2013 - 12:54 PM

I'm sorry that you found the Enumeration discussion irrelevant. The point there was that one technique to get the effect of "friend" classes is to have nested classes. The inner classes have access to the private variables and methods of the outer class.
Was This Post Helpful? 0
  • +
  • -

#14 Muuski   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 18-March 13

Re: C# friend equivalent solution, does this still break encapsulation?

Posted 19 March 2013 - 01:58 PM

View PostSkydiver, on 19 March 2013 - 12:54 PM, said:

I'm sorry that you found the Enumeration discussion irrelevant. The point there was that one technique to get the effect of "friend" classes is to have nested classes. The inner classes have access to the private variables and methods of the outer class.


I have to admit that on a second reading I realized I didn't actually read your post and just skimmed. My apologies. Primarily my concern with nested classes is that they cannot be shared between two classes (at least as far as I've seen/read) so it would only be able to access either Foo or Bar. On the other hand, I suppose I could use the code I showed in my last post and pass an instance of a nested class instead of downcasting ourselves (dangerously) into an exposed interface.

I'm working on an example of this, but haven't finished it yet.
Was This Post Helpful? 0
  • +
  • -

#15 AdamSpeight2008   User is offline

  • MrCupOfT
  • member icon

Reputation: 2298
  • View blog
  • Posts: 9,535
  • Joined: 29-May 08

Re: C# friend equivalent solution, does this still break encapsulation?

Posted 19 March 2013 - 07:37 PM

View PostMomerath, on 19 March 2013 - 02:26 PM, said:

View PostAdamSpeight2008, on 18 March 2013 - 07:52 PM, said:

The source collection is based in as a parameter of the constructor for that collections Enumerator, they still uses public methods on the source collections. No Private members / methods are accessed.


From Queue<T>.Enumerator (nested class in Queue<T>
public bool MoveNext() {
    if (this._version != this._q._version) {
        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
    }
    if (this._index == -2) {
        return false;
    }
    this._index++;
    if (this._index == this._q._size) {
        this._index = -2;
        this._currentElement = default(T);
        return false;
    }
    this._currentElement = this._q.GetElement(this._index);
    return true;
}


both this._q._version and this._q._size are private in Queue<T>


That maybe so, but the scope of private is accessible to anything inside the scoping bounds (the class) Inner class are inside that scope, so have they have access.
Simple scope visibility.

Class_Outer 
{ Class_Inner
  {
  } 
}



The Class_Inner has access to private members of Class_Outer but the inverse is not true. Class_Outer has not access to private members of Class_Inner.

What the OP is wanting is where independent classes have access to private members of the other class.
Class_A {}
Class_B {}



Which I think is possible (without reflection). As there is an attribute
InternalsVisibleToAttribute (MSDN Article)
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2