Sign in to follow this  
storage

[.net] Accessing private field of class X from class Y

Recommended Posts

I have a simple question, It it possible for class X (the kernel class) to access the private m_ProcessID field of class Y (the process class)? Something like friend classes of C++? Thanks in advance!

Share this post


Link to post
Share on other sites
You can do this with reflection, but it's a bit cumbersome, so you might want to make a public (or internal) getter instead.

y.GetType().GetField("m_ProcessID", BindingFlags.Instance|BindingFlags.NonPublic).GetValue(y)

Share this post


Link to post
Share on other sites
I can't use a public getter, because I want ONLY the kernel class to be able to set the m_ProcessID field.

I tried making m_ProcessID internal, but I can't seem to understand how it works. I can access Process.m_ProcessID from any class in the project.

Thanks for your help! I will try the snippet you posted.

Share this post


Link to post
Share on other sites
Yes you CAN do it. You could make the field public, there are other ways also. But that is find of ruining the reason you put things in classes in the first place. As a general rule you should not allow direct access to members of another class. Make the access go through the class that has the member, this protects the data and the way you access it.

theTroll

Share this post


Link to post
Share on other sites
Might be a good chance to use C# Properties. Basically they allow you to make data fields public, but still determine how they are accessed and mutated. I know it's not quite what you are looking for because the data isn't shared exclusively between two classes, but it's a lot safer than just declaring data members public.

Share this post


Link to post
Share on other sites
One way to partition the access of a class is to use interfaces. So you'd have one interface that exposes what the kernel sees, and then one interface which exposes what everyone else can see. Then you just make sure that nobody access the class from but only the interfaces. So the kernel would have an object of type IKernelView and the others would use IOthersView (or something).

This is an unfortunate omission in C#, but I hardly think friends are the solution. Something like what Eiffel does (where each feature of class defines who it exposes itself to) would probably be ideal.

Share this post


Link to post
Share on other sites
Quote:
Original post by TheTroll
You can use Interfaces in C#, the syntax is just different.

theTroll


Yeah, but interfaces don't really solve the problem. What if another class casts the interface to the type of the base class? Then they could see and access everything public.

I think 'internal' is the best way to go. If you don't already know, internal makes it so only that assembly can access it. If you define your kernel and class Y in one project that is compiled to a .dll and your other code in another project in the same solution, then internal things in Y are visible to Kernel (and other classes in your 'framework/engine' project) but not to your main program.

A nice side effect is that it encourages you to split functionality into neat, well-defined blocks.

Share this post


Link to post
Share on other sites
Quote:
Original post by storage
I can't use a public getter, because I want ONLY the kernel class to be able to set the m_ProcessID field.

So? Just don't provide a setter:


public int ProcessID
{
get{ return m_ProcessID; }
}

Share this post


Link to post
Share on other sites
Methods I can think of:

1. Reflection is one sure fire way to do it. It is cumbersome, but it is also the most straightforward.

BeerHunter provided sample code for accessing a field. This will let you access a property; the only real change is the BindingFlags used.


PropertyInfo propertyInfo = objectToSet.GetType().GetProperty("NameToSet",
BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.NonPublic);
propertyInfo.SetValue(objectToSet, valueToSet);


2. Have the child contact the kernel for its process identifier using a callback routine. This allows the processing of the assignment to occur within the child, but lets the "friend" class have the last say. You could process the callback routine within the constructor.

3. Create a separate factory function inside the child class which is responsible for creating new child objects. Pass to the factory function the identifier that is to be assigned and allow the factory to produce the object. Since the factory is a part of the class it has access to all data in the class, private, protected, or public.

4. Wrap the field you're trying to set in an accessor. When the value is changed or attempted to be changed, take action. If the value isn't set yet, allow it to be set. If the value is set, perform authentication as necessary to verify that the value should be overridden. If necessary you can even examine the stack trace to determine what the calling objects are but be aware that release optimizations often change the stack trace; in debug mode it works flawlessly because inlining isn't performed, etc. In release mode four functions can be inlined in a row, giving you results which are not expected.

#2 seems to be the most stable and proper. It allows the process to retain contrl of when the identifier is changed, but it does remove the ability of the kernel from being able to change the process ID on the fly. This may be desired -- so this may not be a bad thing.

(I read your post as "access" being to change, read and write, not read only. Several solutions have been suggested above for read only access. Most of mine are more concerned with the kernel setting the process ID.)

Share this post


Link to post
Share on other sites
Quote:
Original post by TheTroll
You can use Interfaces in C#, the syntax is just different.

theTroll


(I assume that was a reply to my post)

I didn't mean to imply you couldn't. However, interfaces really don't solve the problem (I suggested them as a stop-gap solution to get around the limitations in C#).
What I meant to say was that I would have liked it if C# worked like Eiffel in this regard where you can control what gets exported to whom with very fine grained control ("ANY" for "public", "NONE" for private, and "KERNEL" for just the class KERNEL etc.). This is very handy and gets rid of some of the rather ugly and cumbersome design patterns used to emulate this (e.g. splitting something which is logically a single object, like a monster, into two different classes: a view and a model -- Eiffel style you'd just have two different sets of operations on the same object, but only the renderer class can access the view interface etc.)

Share this post


Link to post
Share on other sites
If you want to do this, you typically have an abstraction problem.

Questions worth pondering:

-Why does the kernel need to access the process ID ? Could this be avoided ? How ?
-Why shouldn't the other classes access the process ID ? What makes the kernel so special then ? Would the process class be a candidate for a nested class which is exposed trough a proxy to other classes ?
-Are you missing a project delimitation ? Do the classes that you want to deny access to the process ID semantically belong in the same assemblies ? (Hint, if you have Kernel and TwoHeadedMonster in the same assemblies, you have a problem.)

Lastly, if you feel it can help, you might look into friend assemblies.

Share this post


Link to post
Share on other sites
You can use "internal" if they are in the same assembly or use friend assemblies if they generally are trusted assemblies. You shouldn't expect access to a private member of an arbitrary assembly, though.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this