2013-05-15 11 views
14

Ich möchte eine bestimmte Methode in einer Klasse nur für eine bestimmte Klasse zugänglich sein. Zum Beispiel:Limit-Methode nur von einer bestimmten Klasse aufgerufen werden

public class A 
{ 
    public void LimitedAccess() {} 
    public void FullAccess() {} 
} 

public class B 
{ 
    public void Func() 
    { 
    A a = new A(); 
    a.LimitedAccess();  // want to be able to call this only from class B 
    } 
} 

public class C 
{ 
    public void Func() 
    { 
    A a = new A(); 
    a.FullAccess();   // want to be able to call this method 
    a.LimitedAccess();  // but want this to fail compile 
    } 
} 

Gibt es ein Schlüsselwort oder Attribut, das ich verwenden kann, um dies zu erzwingen?

UPDATE:

Aufgrund bestehenden Systemkomplexität und Zeitdruck, ich brauchte eine geringe Auswirkung Lösung. Und ich wollte etwas zur Kompilierzeit angeben, dass LimitedAccess() nicht verwendet werden konnte. Ich vertraue Jon Skeets Antwort, dass genau das, wonach ich gefragt hatte, nicht in C# erledigt werden konnte.

Die Frage und Jons Antwort sind gut für diejenigen, die später darauf stoßen. Und die Tatsache, dass dieses Design riecht, kann hoffentlich niemanden davon abbringen, sich für etwas wie diese als Lösung zu entscheiden.

Wie in einem Kommentar erwähnt, ist die C# friend Konversation nützlich, wenn Sie versuchen, eine ähnliche Situation zu lösen.

Wie für meine besondere Lösung: "Warum würde A die Logik von B enthalten" (gefragt von @sysexpand in Kommentaren). Das ist der Haken. B.Func() wurde während des gesamten Systems, an dem ich arbeite, aufgerufen, aber es wurde hauptsächlich mit einem Singleton von A betrieben. Also, was ich am Ende getan habe, war BFunc() in A zu verschieben und A.LimitedAccess() privat zu machen. Es gab ein paar andere Details, um zu umgehen, wie es immer gibt, aber ich habe eine Low-Impact-Lösung, die mir Kompilierungsfehler bei Anrufern A.LimitedAccess().

Danke für die Diskussion.

+0

Warum möchten Sie dies tun? –

+0

Ich habe eine große Klasse "A", die weitgehend in einem System verwendet wird. Die Klasse "B" hat andere Abhängigkeiten, hat aber den Standard/besten Weg, B.LimitedAccess() zu verwenden. Ich möchte mit 'B.Func()' erzwingen wann immer möglich. – jltrem

+0

siehe http://stackoverflow.com/questions/203616/why-does-c-sharp-not-provide-the-c-style-friend-keyword Sie sollten "LimitedAccess" als intern markieren und Missbrauch durch Code feststellen Rezension. – Yaur

Antwort

18

Nein. Das einzige, was Sie tun könnten, wäre LimitedAccess eine private Methode zu machen und die Klasse B innerhalb der Klasse A zu verschachteln.

(Ich gehe davon aus Sie alle Klassen in derselben Assembly wollen. Andernfalls Sie A und B in derselben Assembly setzen könnten, und C in einer anderen Baugruppe und LimitedAccess eine internal Methode machen.)

+2

Tatsächlich gibt es eine andere Methode, aber dies erfordert, dass die spezifische Klasse das Objekt erstellt und die erstellte Klasse eine Schnittstellenimplementierung als out-Methode ('new A (out limitedAccessMethods) ') verfügbar macht. Dies erfordert natürlich eine private verschachtelte Klasse in "A", die die Schnittstelle implementiert, aber den Zugriff nur durch die Erstellungsklasse erlaubt. Es ist jedoch fraglich, ob es vom Design her schön ist. Und natürlich ist es begrenzt. –

0

Es ist gegen OOP-Best Practices, solch ein Design zu machen. Klassenmethoden sollen nicht davor geschützt werden, angerufen zu werden.

Wenn Ihr Entwurf Kontrolle über den Aufruf einer Methode erfordert, sollte die Kontrolle durch Testen der Argumente ausgeübt werden - Anrufer, der berechtigt ist, einen Anruf zu tätigen, würde das Zauberwort als Argument "kennen".

+1

Jon hat zwei völlig geeignete Mittel zur Verfügung gestellt. Ihre Methode ist dagegen absolut der falsche Weg. Sie erhalten keine Kompilierzeitunterstützung, sie kann leicht in die Verwendung eines Decompilers zerlegt oder gehackt werden, und die Benutzer der Klasse haben jetzt eine verwirrende API-Methode, um zu sehen, dass sie sie eigentlich nicht verwenden sollen. – Servy

+0

Die Frage war: "Ich möchte eine bestimmte Methode in einer Klasse nur für eine bestimmte Klasse zugänglich sein." Sie versuchen es einfach nicht ... Die andere Sache ist, eine Methode intern zu deklarieren und dann von ALLEN Klassen in der Assembly aus darauf zuzugreifen. Aber das war nicht die Frage. –

+0

Und das löst dieses Problem nicht; Die Methode wäre immer noch überall zugänglich, sie würde einfach nicht richtig funktionieren, wenn sie nur irgendwo ohne das richtige magische Argument verwendet würde. Beide Lösungen von Jon beinhalten die Beschränkung der Zugänglichkeit der Methode auf diejenigen, die keinen Zugriff haben sollten. – Servy

2

Angenommen, Sie möchten nur den Zugriff auf Methoden und Variablen für eine spezifische Instanz beschränken, können Sie diesen Effekt über eine Schnittstelle erzielen. Es verhindert jedoch nicht, dass jemand seine eigene Instanz der Klasse erstellt. Zu diesem Zeitpunkt haben sie vollen Zugriff auf diese Instanz.

public interface IA 
{ 
    void FullAccess(); 
} 


public class A 
{ 
    public void LimitedAccess() {} //does not implement any interface 
    public void FullAccess() {}  //implements interface 
} 


public class B 
{ 
    private A a = new A(); 

    public IA GetA() 
    { 
    return (IA)a; 
    } 

    public void Func() 
    { 
    /* will be able to call LimitedAccess only from class B, 
     as long as everybody else only has a reference to the interface (IA). */ 
    a.LimitedAccess();  
    } 
} 


//This represents all other classes 
public class C 
{ 
    public IA Ia; 

    public void Func() 
    { 
    Ia.FullAccess();   // will be able to call this method 
    Ia.LimitedAccess();  // this will fail compile 
    } 
} 

public static class MainClass 
{ 
    static void Main(string[] args) 
    { 
    B b = new B(); 
    b.func(); 
    C c = new C(); 
    c.Ia = b.GetA(); 
    c.func(); 
    } 
} 
0

Vielleicht ist dies ein Workaround.

Verwenden Sie die System.Runtime.CompilerServices, und dann können Sie entweder den Namen der aufrufenden Funktion und/oder die Datei überprüfen, in der die aufrufende Funktion definiert ist. Wenn Sie eine Klasse pro Datei haben, könnte der Dateiname eine Ersatznummer für den Klassennamen sein. Überprüfen Sie es und blockieren Sie den Anruf.

internal void MySecretFunction (string something, 
    [CallerMemberName] string memberName = null, 
    [CallerFilePath] string filePath = null, 
    [CallerLineNumber] int lineNumber = 0) { 
    if (!filePath.EndsWith(@"\goodClass.cs")) return; 

    // else do something 
} 
Verwandte Themen