C# Friend classes and OOP Composition
Asked Answered
C

6

12

Given class A, which contains sets of raw data, and class B, which contains a re-organized version (GUI ready) of that data I would like to make the raw data in A visible in B.

Clearly the raw data in class A is contained in private members. I would like to make that data visible in B though the use of something akin to the C++ friend classes method.

How can I approach this?

Thank you.

Casar answered 1/2, 2010 at 16:36 Comment(0)
S
9

Strictly speaking, you can't define a specific class (or list of classes) that you can expose the data to. You can, however, use the internal access modifier instead of private, which makes the members available to any class in the same assembly.

That being said, you should strongly consider exposing these members through properties rather than fields (which is what I'm guessing you're planning on exposing). Doing this will allow the class to define exactly how that information can be exposed to other classes and what--if anything--should happen when another class changes the data.

Snowblind answered 1/2, 2010 at 16:39 Comment(4)
internal + properties = safe.Odontograph
This seems like a case for either internal properties or possibly an internal interface that the source data class A implements that allows B to access some of the private members without being overly tied to A.Hassi
@LBushkin: An internal interface is certainly a solution, but it seems unnecessary unless there's actually going to be more than one class implementing it.Snowblind
That's why I said or possibly in my comment - since it can be overkill. However, UI-adaptive model classes are created sometimes for each UI view that is needed, as in the MVVM model used for Silverlight/WPF apps. In these cases, internal interfaces can make things a bit more loosely coupled, and easier to change.Hassi
P
6

May be this might help you..

public class A
{
    public A() { }

    public string AccessData(object accessor)
    {
        if (accessor is B)
            return "private_data";
        else
            throw new UnauthorizedAccessException();
    }
}

public class B
{
    public B() { }

    private void AccessDataFromA()
    {
        Console.WriteLine(new A().AccessData(this));
    }
}
Patroclus answered 16/3, 2010 at 4:54 Comment(2)
This is a clever way to implement the semantics of friend. I don't always use friend, but when I do, I use this accessor pattern :-)Blastoff
But this just breaks compile time safety. I could pretty much use any class to AccessData here and the compiler wouldn't complain.Keystone
W
1

You could define both in an assembly and mark the fields in A as "internal".

A more OO approach is to provide a set of public methods in A that allow access to the data (or a subset of the data), typically via simple properties.

Westsouthwest answered 1/2, 2010 at 16:40 Comment(0)
C
0

Depending on your structure you may be able to use Partial classes. This would mean that the Data and UI are actually both within the same class, but you have them within different files.

If that doesn't work for you, then you've got internal scoped variables as an alternative or working with Datasets that the UI represents in a more generic manner.

Cynic answered 1/2, 2010 at 16:53 Comment(0)
W
0

The old method (pun intended) would be to define simple getvalue() and setvalue() functions to return that value so that these values would become inaccessible without the use of these functions, in C# these functions are predefined members called properties.

class TestMethod{ 
private int Secret;

get { return Secret;}
set { Secret = value;}
}

The other method is to, as others have stated before me, just use the internal modifier.

Wendalyn answered 16/3, 2010 at 4:41 Comment(0)
S
0

Another approach would be something along these lines. Notice that the getter and setter here specify class B as a key so other classes cannot reach to the inner state of class A.

public class Program
{
    public static void Main()
    {
         var a = new A(29);
         var (getter, setter) = A.GetAndSetOnlyForB(a);
    
         Console.WriteLine(getter(new B())); // 29
         setter(new B(), 2);
         Console.WriteLine(getter(new B())); // 2

         getter(new C()); // compile error, cannot do that
         setter(new C(), 9); // compile error, cannot do that
    }
}

sealed class A
{
    private int _hiddenInt;
    public A(int hiddenInt)
    {
        _hiddenInt = hiddenInt;
    }
    
    public static (Func<B, int>, Action<B, int>) GetAndSetOnlyForB(A obj)
    {
        return ((key) => obj._hiddenInt, (key, arg) => { obj._hiddenInt = arg; });
    }
}

sealed class B
{
}

sealed class C
{
}

Sverre answered 27/9, 2021 at 14:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.