Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# - How to prevent a reference being taken to a class member?

Tags:

c#

I have a class (myClass) that contains a private class member (currentData of type myData). I have a property (CurrentData) that allows "get"ting that member. I want to allow users to call functions on currentData but prevent them from taking an external reference to it. Eg.

myClass a = new myClass();

// This is OK
a.CurrentData.somefunc();

// This is what I dont want
myData m = new myData();
m = a.CurrentData;
// ... some time passes here...
m.someFunc();

While I understand they reference the same object. I dont want a reference being kept outside of my class to an internal member as the internal member could change unexpectedly.

Is this possible? I have been away from c# so long I cant remember how it all works!

like image 463
Ashley Duncan Avatar asked Dec 06 '22 16:12

Ashley Duncan


2 Answers

There's not a way to make

a.CurrentData.somefunc();

legal but

m = a.CurrentData;

illegal. a.CurrentData.somefunc(); essentially returns an inline reference to a.CurrentData and then calls somefunc() on that reference.

If you want to prevent references to the internal object then you'll have to add methods to the containing class that then pass through to the contained object:

public void DoSomeFuncWithCurrentData()
{
   this.currentData.someFunc();
}

myClass a = new myClass();

a.DoSomeFuncWithCurrentData();
like image 199
D Stanley Avatar answered Dec 15 '22 00:12

D Stanley


There is no direct way to "forbid" references.

However, there are a few possible workarounds:

  • Create proxy methods: Don't allow public access to the CurrentData property at all. Create a proxy method for every method that can be called on CurrentData:

    myClass a = new myClass();
    a.SomeFuncOnCurrentData();
    

    That way you don't expose the inner workings of your class to the outside. The drawback is that you have to write a lot of boilerplate code (or use some third-party tool which writes the boilerplate code for you).

  • Return a copy: Replace your CurrentData property with a GetCurrentData method and return a new copy of your internal object on every invocation. That way, the user can operate on the "old" data as long as he wants, and the user's object is disconnected from your internal object.

  • Replace your internal object and leave the old one intact: Make MyData an immutable class. When CurrentData changes, don't modify MyData, create a new MyData object instead. This has the same effect as the previous point (returning a copy), but you can keep using a property which does not need to create a copy on each invocation.

  • Invalidate the old internal object: When CurrentData changes, perform the following steps:

    • internally use a new instance of MyData,
    • set a flag on the old instance, which causes someFunc to throw a ObjectExpiredException.
like image 32
Heinzi Avatar answered Dec 14 '22 22:12

Heinzi