两个类,S和R以及消息M(实现为类,委托或其他)。
我可以借助C#中的接口来满足以下要求吗?如果是,怎么做?
这对我来说听起来很简单和自然,但无论我如何努力在SO或网上搜索,我都找不到任何有用的东西。我发现的唯一一件事是对工厂模式的引用,我认为这并不适用于此,因为问题不在于构建S,R或X.
当然,我也很感激任何其他不涉及接口的解决方案。
顺便说一句:虽然听起来有点像,但这既不是家庭作业,也不是专业背景。我只是一个爱好者程序员,试图探索我喜欢的语言的可能性。
修改
为了提供(假设的)代码示例:对我来说理想的方式是能够编写如下所示的(伪)代码。 我知道该语言不支持。这就是为什么我要求找到模式或实现相同目标的东西。
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
}
}
答案 0 :(得分:1)
我已经对此进行了评论,不确定这是否是您要查找的内容,但您可以使用泛型来限制类型参数。这会检查编译时间。
public interface IOtherInterface
{
}
public interface IAnInterface<T> where T : IOtherInterface
{
void DoSomething(T parameter);
}
public class ThisWontWork
{
}
var other = new OtherInterface();
var an = new AnInterface();
an.DoSomething(other); // this works
var wontWork = new ThisWontWork();
an.DoSomething(wontWork); // will not build
省略了接口的类,但我想你明白了。
答案 1 :(得分:1)
从我的评论开始,包装非泛型类S和R,然后将类型约束应用于这些包装类。
更新:工作代码。实际上不需要泛型或包装类。只是实现接口
using System;
public interface IM
{
void SendM(IRM target, string message);
}
public interface IN
{
void SendN(IRN target, string message);
}
public interface IRM
{
string ReceiveM(IM source, string message);
}
public interface IRN
{
string ReceiveN(IN source, string message);
}
public class S : IM
{
public void SendM(IRM target, string message) => target.ReceiveM(this, message);
// Argument 1 cannot convert from S to X :-
public void SendN(IRN target, string message) => target.ReceiveN(this, message); }
public class X : IN
{
public void SendN(IRN target, string message) => target.ReceiveN(this, message);
// Argument 1 cannot convert from X to S :-
public void SendM(IRM target, string message) => target.ReceiveM(this, message); }
public class Receiver : IRN, IRM
{
public string ReceiveM(IM source, string message)
{
throw new NotImplementedException();
}
public string ReceiveN(IN source, string message)
{
throw new NotImplementedException();
}
}
public class Program
{
public static void Main()
{
var r = new Receiver();
var s = new S();
s.SendM(r, "message via M");
var x = new X();
x.SendN(r, "message via N");
// s.SendN(r,"does not compile nor in intellisense");
}
}
答案 2 :(得分:1)
访客模式大纲:
请参阅https://dotnetfiddle.net/MfGWqw
Function lastDay(year As String, month As String) As Date
Dim ld As Date
If LCase(month) = "all" Then month = "DEC"
ld = DateValue("01 " & month & Space(1) & year)
Dim d As Double
d = WorksheetFunction.EoMonth(ld, 0)
ld = CDate(d)
lastDay = ld
End Function
我没有在该示例中使用接口,但当然,可以。我只是想概述满足您要求的模式。我希望你需要根据自己的需要进行调整。
编辑:回答你的评论...... 如果你害怕S中的恶意实现,你可以使用explicit interface implementation解决这个问题。一个例子:
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);
}
}
然后更改public interface IMReceiver
{
void accept( S sender, M message);
}
:
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 ...
}
:
S
我在这里只为S和M做了这个例子,但你可能想对X和N做同样的事情。
答案 3 :(得分:0)
由Fildor(接受)answer提供 - 基本上访问者模式加上接收方通过显式接口实现的额外访问限制 - 我还准备了一个完整的工作示例这说明了它。
滥用(即,来自禁止发件人的发送消息)的唯一方法是通过显式转换到与创建相应虚拟发件人对象相关的其中一个接口。作为一种安全风险,我认为这是可以接受的,因为它很难被偶然绕过。
public interface IMReceiver
{
void MessageM(MSender sender);
}
public interface INReceiver
{
void MessageN(NSender sender);
}
public class Receiver: IMReceiver, INReceiver
{
string name;
public Receiver(string newName) {name = newName;}
void IMReceiver.MessageM(MSender sender) {Console.WriteLine(name+" received Message M from "+sender.Name);}
void INReceiver.MessageN(NSender sender) {Console.WriteLine(name+" received Message N from "+sender.Name);}
}
public class MSender
{
void sendMessageMTo(IMReceiver r) {r.MessageM(this);}
public readonly string Name = "an MSender";
Receiver r1 = new Receiver("Alice");
Receiver r2 = new Receiver("Bob");
public void JustDoIt()
{
sendMessageMTo(r1);
sendMessageMTo(r2);
// thinkable abuses:
// sendMessageNTo(r1); // is simply not defined
// r1.MessageN(this); // does not compile without cast
// (r1 as INReceiver).MessageN(this); // does not compile with this Sender type
(r1 as INReceiver).MessageN(new NSender()); // possible, but unlikely to happen by accident
}
}
public class NSender
{
void sendMessageNTo(INReceiver r) {r.MessageN(this);}
public readonly string Name = "an NSender";
Receiver r3 = new Receiver("Clive");
Receiver r4 = new Receiver("Dan");
public void DoItDifferently()
{
sendMessageNTo(r3);
sendMessageNTo(r4);
}
}
并在Main:
MSender ms = new MSender();
NSender ns = new NSender();
ms.JustDoIt();
ns.DoItDifferently();