用于限制对类的访问的接口的角色

问题描述 投票:0回答:4

两个类,S和R以及消息M(实现为类,委托或其他)。

我可以借助C#中的接口来满足以下要求吗?如果有,怎么样?

  1. S的任何对象都应该能够将M发送给R的任何对象
  2. 任何其他类X的任何对象都不能将M发送给R的任何对象
  3. S的对象不能向R的对象发送任何其他消息N(尽管R可能从其他类的对象接收其他消息类型)
  4. 任何违反上述规定发送M或N的企图都会导致编译错误(即应进行静态检查)

这对我来说听起来很简单和自然,但无论我如何努力在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
    }
}
c# interface separation-of-concerns visitor
4个回答
1
投票

访客模式的大纲:

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);
    }
}

我没有在那个例子中使用接口,当然,你可以。我只是想概述满足您要求的模式。我希望你需要根据自己的需要进行调整。

编辑:回答你的评论......如果你害怕S中的恶意实施,你可以用explicit interface implementations解决这个问题。一个例子:

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

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
    }
}

我这里只为S和M做了这个例子,但你可能想对X和N做同样的事情。

https://dotnetfiddle.net/b14BOc


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

省略了接口的类,但我想你明白了。

在这里阅读更多:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters


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");
    }
}

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);
    }
}

在主要:

MSender ms = new MSender();
NSender ns = new NSender();

ms.JustDoIt();
ns.DoItDifferently();
© www.soinside.com 2019 - 2024. All rights reserved.