簡體   English   中英

接口的作用,用於限制對類的訪問

[英]Role of interfaces for restricting access to a class

兩個類,S和R,以及消息M(實現為類,委托或任何形式)。

我可以借助C#中的接口滿足以下要求嗎? 如果是,怎么辦?

  1. S的任何對象應能夠將M發送給R的任何對象
  2. 其他任何X類的對象都不能將M發送給R的任何對象
  3. S的物體不應能夠任何其他消息發送ÑR的對象(盡管可能ř從其他類對象接收其它消息類型)
  4. 違反上述規定發送M或N的任何嘗試均將導致編譯器錯誤(即應進行靜態檢查)

這聽起來很簡單自然,但是無論我多么努力在SO或Web上進行搜索,我都找不到有用的東西。 我發現的唯一內容是對Factory模式的引用,我認為它在這里並沒有真正應用,因為問題不在於構造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
    }
}

好吧,我已經對此發表過評論,不確定這是否是您要尋找的,但是您可以使用泛型來限制類型參數。 這會檢查編譯時間。

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/zh-cn/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters

根據我的評論,包裝非泛型類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");
    }
}

訪客模式概述:

參見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中的惡意實現,則可以使用顯式接口實現 s來解決。 一個例子:

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

通過Fildor的(可接受的) 答案 (基本上是一種訪客模式,再加上通過顯式接口實現的Receiver方面的附加訪問限制),我還准備了一個完整的工作示例來對其進行說明。

濫用(即從禁止的發送者發送消息)新創建的接收者的唯一方法是通過顯式強制轉換為與各個偽發送者對象相關的接口之一。 作為安全隱患,我認為這是可以接受的,因為很難偶然繞過它。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM