I need to implement a bit of the “friend” function in C ++ in C # and look for ideas.
Consider two very close classes: Node and NodePart. Nodes contain NodeParts, which are added through public AddPart () calls from other systems with parts that these systems create. Node must “reach” NodePart in order to make some very specific notifications that NodePart will propagate through separate virtual protected methods to any derived classes after some processing. (For those familiar with programming component-based game objects, this is the same.)
I would like NodePart to give Node a way to get these few notification methods, while avoiding any other types in the system. Node does not need to access other internal components of NodePart, just forward some private notifications.
Now, putting these classes in an assembly and using the “internal” one will obviously do the trick, but I'm looking for a better example than this. (I am not interested in creating new assemblies for each set of classes with which I would like to do this in the future.)
Besides reflection + invoke, which is bright and fragile, what other patterns can you come up with to solve this problem here? My common sense tells me that interfaces are part of the solution, but I can't think about how.
(Note: I have everything in order with security through obscurity. This system should not be 100% proven against misuse - enough to prevent people from doing what they should not. We are not building defibrillators here.)
Update:. Most of the answers below require multiple builds. As I mentioned above, I would really like to avoid this. I do not want to put one system on the assembly. We have enough things as they are, and I cannot go down the IL communication route due to our use of XAML. But thanks for the answers anyway. :)
Update 2: I came across in Linqpad and suggested several options based on the answers below. What do you like the worst and why?
Option 1: Deprecated
#pragma warning disable 612 // doc this public sealed class Node : NodePart.SystemAccess { #pragma warning restore 612 NodePart _part; public NodePart Part { get { return _part; } set { _part = value; NotifyAdded(_part); } } } public class NodePart { void NotifyAdded() { Console.WriteLine("Part added"); } [Obsolete] public class SystemAccess // doc this { protected void NotifyAdded(NodePart part) { part.NotifyAdded(); } } }
Not bad. A little strange, but the strangeness is very limited. I am inclined to this, because it is much more compact than the next option.
Option 2: Access + Hack
public sealed class Node { static readonly NodePart.ISystemAccess _systemAccess; static Node() { _systemAccess = (NodePart.ISystemAccess)typeof(NodePart) .GetNestedTypes(BindingFlags.NonPublic) .Single(t => t.Name == "SystemAccess") .GetConstructor(Type.EmptyTypes) .Invoke(null); } NodePart _part; public NodePart Part { get { return _part; } set { _part = value; _systemAccess.NotifyAdded(_part); } } } public class NodePart { void NotifyAdded() { Console.WriteLine("Part added"); } internal interface ISystemAccess { void NotifyAdded(NodePart part); } class SystemAccess : ISystemAccess { void ISystemAccess.NotifyAdded(NodePart part) { part.NotifyAdded(); } } }
Hacka hacka hacka. In my original version there was no reflection + invoke and it would rely on SystemAccess, which would not be obvious. It may be good, but I kind of like a little extra security that I get here, although it probably is not needed.