Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to get access to private members of nested class?

Background: I have enclosed (parent) class E with nested class N with several instances of N in E. In the enclosed (parent) class I am doing some calculations and I am setting the values for each instance of nested class. Something like this:

n1.field1 = ...;
n1.field2 = ...;
n1.field3 = ...;
n2.field1 = ...;
...

It is one big eval method (in parent class). My intention is -- since all calculations are in parent class (they cannot be done per nested instance because it would make code more complicated) -- make the setters only available to parent class and getters public.

And now there is a problem:

  • when I make the setters private, parent class cannot acces them
  • when I make them public, everybody can change the values
  • and C# does not have friend concept
  • I cannot pass values in constructor because lazy evaluation mechanism is used (so the instances have to be created when referencing them -- I create all objects and the calculation is triggered on demand)

I am stuck -- how to do this (limit access up to parent class, no more, no less)?


I suspect I'll get answer-question first -- "but why you don't split the evaluation per each field" -- so I answer this by example: how do you calculate min and max value of a collection? In a fast way? The answer is -- in one pass. This is why I have one eval function which does calculations and sets all fields at once.

like image 876
greenoldman Avatar asked May 12 '10 08:05

greenoldman


People also ask

Can nested classes access private members?

A nested class is a member of its enclosing class. Non-static nested classes (inner classes) have access to other members of the enclosing class, even if they are declared private.

How do I access private nested classes?

Accessing the Private Members Write an inner class in it, return the private members from a method within the inner class, say, getValue(), and finally from another class (from which you want to access the private members) call the getValue() method of the inner class.

Can nested classes access private members in Java?

Not only does the nested class have access to the private fields of the outer class, but the same fields can be accessed by any other class within the package when the nested class is declared public or if it contains public methods or constructors.

How do you access private members of a class?

2. Private: The class members declared as private can be accessed only by the member functions inside the class. They are not allowed to be accessed directly by any object or function outside the class. Only the member functions or the friend functions are allowed to access the private data members of the class.


4 Answers

You could declare inside E a private interface IN, explicitly implemented by N. This interface would expose the members of N accessible only by E :

public class E
{
    public void Foo()
    {
      IN n = new N();
      n.Field1 = 42;
    }

    public class N : IN
    {
        private int _field1;

        int IN.Field1
        {
            get { return _field1; }
            set { _field1 = value; }
        }
    }

    private interface IN
    {
        int Field1 { get; set; }
    }
}
like image 148
Thomas Levesque Avatar answered Oct 01 '22 11:10

Thomas Levesque


If it's possible for you to put the parent and child classes in another assembly, you can make use of internal for the setters. That's generally how this is dealt with in the wild.

EDIT:

Thomas Levesque's answer gave me an idea:

class Program
{
    static void Main(string[] args)
    {
        E myE = new E();

        Console.WriteLine("E.N1.Field1 = " + myE.N1.Field1);
        Console.WriteLine("E.N2.Field1 = " + myE.N2.Field1);
    }

    public interface IN
    {
        int Field1 { get; }
    }

    public class E
    {
        private N _n1 = new N();
        private N _n2 = new N();

        public E()
        {
            _n1.Field1 = 42;
            _n2.Field1 = 23;
        }

        public IN N1
        {
            get { return _n1; }
        }

        public IN N2
        {
            get { return _n2; }
        }

        private class N : IN
        {
            private int _field1;

            public int Field1
            {
                get { return _field1; }
                set { _field1 = value; }
            }
        }
    }
}

Depending on how you need to expose the child class N, this could work.

like image 34
Codesleuth Avatar answered Oct 01 '22 10:10

Codesleuth


Another alternative is to leave the members you wish to be private public if your (nested) class is private. If fields of private class is public, its only going to be exposed to the enclosing class.

public class E
{
    public void Foo()
    {
      IN n = new N();
      n.field1 = 42;
    }

    class N : IN
    {
        public int _field1;
    }
}

Now N is only visible to E, so n._field1 being public only matters to E, and you're safe..

like image 7
nawfal Avatar answered Oct 01 '22 12:10

nawfal


This is an old question, but here goes a possible solution that doesn't use interfaces.

You can have a static function in the inner class which sets up delegates in the outer class, like so:

public class Outer {
    private delegate void _operateDlg(Inner inner, bool value);
    private static _operateDlg _validate;

    static Outer() {
        Inner.Init();
    }

    public void Set(Inner inner, bool value) {
        _validate(inner, value);
    }

    public class Inner {
        public bool IsValid {get; private set; }
        public static void Init() {
            Outer._validate += delegate(Inner i, bool value) {
                i.IsValid = value;
            };
        }
    }
}

You can put all kinds of different delegates in the outer class that you assign with the Inner.Init() method, such as methods which return an instance of the Inner class through a private constructor or getters/setters of a particular field.

If you don't mind having an extra Init() static function in your inner class, then this doesn't have to change. But if you don't want the Init() method to be visible, you can use reflection to call it:

using System.Reflection;

public class Outer {
    private delegate void _operateDlg(Inner inner, bool value);
    private static _operateDlg _validate;

    static Outer() {
        typeof(Inner).GetMethod("Init",
            BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, null);
    }

    public void Set(Inner inner, bool value) {
        _validate(inner, value);
    }

    public class Inner {
        public bool IsValid {get; private set; }
        private static void Init() {
            Outer._validate = delegate(Inner i, bool value) {
                i.IsValid = value;
            };
        }
    }
}

I know that one could use Reflection to bypass private access restrictions anyway, but using it just to call one single Init() method which then assigns the appropriate delegates is a much cleaner and more versatile solution in my opinion. The alternative would be calling reflection for every single delegate you might want to create, and even then there could be limitations (such as the inability to create delegates to constructors).

The above solution not only supports wrapping constructors, but it will only use Reflection once in the lifetime of a program, so there shouldn't be a noticeable performance penalty other than the fact that you're using delegates to achieve what should have been allowed as direct access in the first place. I don't know why C# doesn't support this, and I can't think of a good reason why it doesn't.

like image 1
Zoodinger Avatar answered Oct 01 '22 10:10

Zoodinger