1

I have a class with a PictureBox created as followed:

public class Tile
{
    public PictureBox tilePB = new PictureBox(); //properties don't matter in this case
}

I also have a class GameManager. This is like a referee.

I want to make it so the BackColor of Tile.tilePB can only be edited by Gamemanager and nothing else, and no other class.

I currently have a public PictureBox for Gamemanager (to edit) and a public get function for other classes, but I want to actually make this a valid system instead of what I have right now.

Is this even possible? Please include explenation for the required code.

EDIT: I ran into an issue that I hadn't thought off: class Gamemanager is a static class. I do everything in that class via public static functions. Is this still possible? Since this doesn't work.

Sander Koldenhof
  • 956
  • 3
  • 11
  • 21
  • https://stackoverflow.com/questions/614818/what-is-the-difference-between-public-private-protected-and-having-no-access – Honeyboy Wilson May 18 '18 at 15:17
  • Strictly speaking this is not possible. You could *possibly* get the semantics you want by using a property with an internal modifier on the set, but that allows any code in the current assembly access to the setter, not one specific class. – Glorin Oakenfoot May 18 '18 at 15:18
  • I'm wondering if you could pass a "this" keyword to the method in question. Then possibly use Type.GetType() or typeOf() to get the calling class. Differentiate as necessary. I'll test this quickly to make sure it works. – Lee Toffolo May 18 '18 at 15:36
  • I don't think there is an out of the box solution for this. – Tarek May 18 '18 at 15:40
  • you can get some information about the caller using the CallMemberName attributes and a couple of others named similarly that do similar things. There are some constrainsts to them and they might not do what you want but could be worth a look https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/caller-information – Dave May 18 '18 at 15:59

4 Answers4

0

Not sure if this is exactly what you are looking for, but I made this quick test and it seems to be able to differentiate the calling class:

class Program
{
    static void Main(string[] args)
    {
        Type1 something1 = new Type1();
        Type2 something2 = new Type2();

        something1.runTest();
        something2.runTest();

        Console.ReadKey();
    }

    public class Type1
    {
        public void runTest()
        {
            Testing.edit(this);
        }
    }

    public class Type2
    {
        public void runTest()
        {
            Testing.edit(this);
        }
    }

    public static class Testing
    {
        public static void edit(object obj)
        {
            // This is where you test the calling class to make sure
            // it is allowed to edit.
            Console.WriteLine(obj.GetType().ToString());
        }
    }
}
Lee Toffolo
  • 134
  • 1
  • 1
  • 9
  • From what I understand, this is what you mean/how to do it: (in my case) instead of having tilePB public, you have a public function `public void ChangeColor(object obj)`. On Gamemanager, you call that funciton and give `this` as parameter. You check if `obj` is of type Gamemanager. If that is true, change color. Right? – Sander Koldenhof May 18 '18 at 15:56
  • Yes, that was my thinking as it related to your case. The above code was proof of concept, but you got the idea. – Lee Toffolo May 18 '18 at 16:10
0

You can't do this at compile time, but it can be done at runtime:

public class PictureBox
{
    private Color _backColor;

    public void SetBackColor(Color color)
    {
        //getting class type that called this method
        var stackTrace = new StackTrace();
        var stackFrames = stackTrace.GetFrames();

        var callingFrame = stackFrames[1];
        var method = callingFrame.GetMethod();

        //checking if the class type is GameManager
        if (!method.DeclaringType.IsAssignableFrom(typeof(GameManager)))
        {
            throw new FieldAccessException("Only GameManager can set the background color of a PictureBox!");
        }

        _backColor = color;
    }

    public Color BackColor => _backColor;
}

public class Tile
{
    public PictureBox tilePB { get; set; }
}

//example GameManager class
public class GameManager
{
    public void SetBackground()
    {
        var someTile = new Tile()
        {
            tilePB = new PictureBox()
        };

        var someColor = new Color();

        someTile.tilePB.SetBackColor(someColor);
    }
}

//example class that may want to set picturebox background color
public class MaliciousClass
{
    public void SetBackground()
    {
        var someTile = new Tile()
        {
            tilePB = new PictureBox()
        };

        var someColor = new Color();

        someTile.tilePB.SetBackColor(someColor);
    }
}

Then somewhere:

var gm = new GameManager();
var mc = new MaliciousClass();

gm.SetBackground(); //this is fine
mc.SetBackground(); //this will throw an exception

If you don't want to throw an exception or you want to do something different when "not authorized" class is trying to access the SetBackColor method then just replace throw new FieldAccessException() with return or whatever you want.

Bare in mind the approach presented here is inefficent and it just presents that in can be done at runtime and nothing more than that.

0

The only way I can think of where you enforce this at compile time, end up being a bit complicated. I don't think you'll want to do this.

You can create an interface with properties/methods for everything that only the GameManager is allowed to do. You can implement this interface in a private inner class below Tile, and make sure the only way this object is created is by passing in a GameManager that receives it. Now, the only way the access can 'leak' is if the GameManager 'gives away' the object.

public class GameManager {
    public void AddTile(Tile t, Tile.IManagerHook m) {
        m.SomeProperty = "set from manager";
    }
}

public class Tile
{
    public object SomeProperty { get; private set; }

    public Tile(GameManager manager) {
        manager.AddTile(this, new ManagerHook(this));
    }

    public interface IManagerHook {
        object SomeProperty {get; set;}
    }


    private class ManagerHook : IManagerHook {
        private Tile _tile;
        public ManagerHook(Tile t) {
            _tile = t;
        }

        public object SomeProperty {
            get{ return  _tile.SomeProperty;}
            set { _tile.SomeProperty = value; }         
        }
    }
}
gnud
  • 75,794
  • 5
  • 62
  • 77
0

(seems) Simply not possible

After asking several programmers, the way I have coded everything and what I want seems to be simply impossible without immensely complicated code - to the point you are better off refacturing everything. Since class Gamemanager is a static class, there will be no instances of it so you can not check if the 'object' that called it is of class Gamemanager. this also doesn't work since Gamemanager is, agian, static.

Sander Koldenhof
  • 956
  • 3
  • 11
  • 21