Two classes, S and R and a message M (implemented as a class, a delegate or whatever).
Could I satisfy the following requirements with the help of interfaces in C#? If yes, how?
It sounds quite simple and natural to me, but no matter how hard I try and search here on SO or the web, I can't find anything useful. The only thing I have found are references to the Factory pattern, which, I think, doesn't really apply here because the problem is not about construction of S,R or X.
Of course I would also be grateful for any other solution that does not involve interfaces.
BTW: although it sounds a little like it, this is neither a homework assignment, nor is it from a professional context. I am just a hobbyist programmer trying to explore the possibilities of the language I love.
Edit:
In order to provide a (hypothetical) code example: the ideal way for me would be to be able to write (pseudo-)code like below. I know that the language does not support that. That is the reason why I am asking to find a pattern or something that achieves the same thing.
class Receiver
{
permits[MSender] void MessageM(); // <- I know that the "permits[]" access modifier does not exist in C#!!!
permits[NSender] void MessageN();
}
class MSender
{
Receiver r;
public void JustDoIt()
{
r.MessageM(); // compiles successfully
r.MessageN(); // does not compile
}
}
class NSender // totally unrelated to sender despite the similar name
{
Receiver r;
public void DoItDifferently()
{
r.MessageM(); // does not compile
r.MessageN(); // compiles successfully
}
}
An outline of a visitor pattern:
See https://dotnetfiddle.net/MfGWqw
public class Program
{
public static void Main()
{
R recv = new R();
new S().send( recv, new M()); // OK
new S().send( recv, new N()); // Compilation error (line 9, col 3):
// The best overloaded method match for 'S.send(R, M)'
// has some invalid arguments
new X().send( recv, new N()); // OK
new X().send( recv, new M()); // Also compilation error ...
}
}
// Message types
public class M{}
public class N{}
// Receiver
public class R
{
public void accept( S sender, M message){}
public void accept( X sender, N message){}
}
// Sender types
public class S
{
public void send( R receiver, M message )
{
receiver.accept(this, message);
}
}
public class X
{
public void send( R receiver, N message )
{
receiver.accept(this, message);
}
}
I didn't use interfaces in that example, but of course, you could. I just wanted to outline the pattern which satisfies your requirements. I am expecting that you will need to adapt it to your needs.
EDIT: To answer your comment ... If you are afraid of malicious implementations in S, you could address that with explicit interface implementations. An example:
public interface IMReceiver
{
void accept( S sender, M message);
}
then change R
:
public class R : IMReceiver
{
void IMReceiver.accept( S sender, M message){} // <= explicit interface implementation.
// only visible when the reference is of
// that interface type.
public void accept( X sender, N message){} // you would do the same for N ...
}
and S
:
public class S
{
public void send( IMReceiver receiver, M message )
{
// receiver now has only accept( S, M ) available.
receiver.accept(this, message);
// MALICIOUS vv
receiver.accept(new X(), new N()); // compilation error
}
}
I only did it for S and M here for the example, but you'd probably want to do the same for X and N.