2013-05-15 20 views
14

Tôi muốn một phương thức cụ thể trong một lớp chỉ có thể truy cập được bởi một lớp cụ thể. Ví dụ:phương thức giới hạn chỉ được gọi bởi một lớp cụ thể

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

Có từ khóa hoặc thuộc tính mà tôi có thể sử dụng để thực thi việc này không?

UPDATE:

Do hạn chế về hệ thống phức tạp và thời gian tồn tại, tôi cần một giải pháp tác động thấp. Và tôi muốn một cái gì đó để chỉ ra tại thời gian biên dịch mà LimitedAccess() không thể được sử dụng. Tôi tin tưởng câu trả lời của Jon Skeet rằng chính xác những gì tôi đã yêu cầu không thể được thực hiện trong C#.

Câu hỏi và câu trả lời của Jon rất phù hợp với những người có thể chạy qua điều này sau. Và thực tế là mùi thiết kế này hy vọng có thể kéo dài bất cứ ai đi để lựa chọn một cái gì đó như thế này như một giải pháp mong muốn.

Như đã đề cập trong nhận xét, cuộc hội thoại C# friend là đọc hữu ích nếu bạn đang cố gắng giải quyết một tình huống tương tự.

Đối với giải pháp cụ thể của tôi: "tại sao A chứa logic B" (được hỏi bởi @sysexpand trong nhận xét). Đó là chà. B.Func() được gọi là trong toàn bộ hệ thống mà tôi đang làm việc, nhưng nó chủ yếu hoạt động trên một singleton của A. Vì vậy, những gì tôi đã kết thúc làm là di chuyển B 's Func() vào A và làm cho A.LimitedAccess() riêng tư. Có một vài chi tiết khác để làm việc xung quanh, như mọi khi, nhưng tôi có một giải pháp tác động thấp đã cho tôi các lỗi biên dịch thời gian trên người gọi đến A.LimitedAccess().

Cảm ơn bạn đã thảo luận.

+0

Tại sao bạn muốn thực hiện việc này? –

+0

Tôi có một lớp lớn 'A' được sử dụng rộng rãi trong toàn bộ hệ thống. Lớp 'B' có các phụ thuộc khác nhưng có một cách tiêu chuẩn/tốt nhất để sử dụng B.LimitedAccess(). Tôi muốn thực thi bằng cách sử dụng 'B.Func()' bất cứ khi nào có thể. – jltrem

+0

xem http://stackoverflow.com/questions/203616/why-does-c-sharp-not-provide-the-c-style-friend-keyword bạn nên đánh dấu 'LimitedAccess' là nội bộ và bắt lạm dụng của nó thông qua mã ôn tập. – Yaur

Trả lời

18

No. Điều duy nhất bạn có thể làm là tạo LimitedAccess một phương pháp riêng và lớp tổ B trong lớp A.

(tôi giả sử bạn muốn tất cả các lớp trong cùng một assembly. Nếu không, bạn có thể đặt AB trong cùng một assembly, và C trong một hội đồng khác nhau, và làm cho LimitedAccess một phương pháp internal.)

+2

Trên thực tế có một phương thức khác, nhưng điều này đòi hỏi rằng lớp cụ thể tạo ra đối tượng và lớp được tạo ra làm lộ ra một giao diện thực hiện như một phương thức ('new A (out restrictedAccessMethods)'). Tất nhiên điều này đòi hỏi một lớp lồng nhau riêng trong 'A' mà thực hiện giao diện nhưng cho phép truy cập chỉ bởi lớp tạo. Tuy nhiên nó là vấn đề nếu nó tốt đẹp từ một quan điểm thiết kế của xem. Và tất nhiên là hạn chế. –

0

Nó là chống lại thực hành tốt nhất OOP để thực hiện một thiết kế như vậy. Các phương thức của các lớp không được bảo vệ khỏi bị gọi.

Nếu thiết kế của bạn yêu cầu kiểm soát việc gọi phương thức, thì kiểm soát phải được thực hiện bằng cách kiểm tra các đối số - người gọi được phép thực hiện cuộc gọi sẽ "biết" từ ảo thuật để chuyển làm đối số.

+1

Jon đã cung cấp hai phương tiện hoàn toàn phù hợp để làm điều này. Phương pháp của bạn, mặt khác, là hoàn toàn sai lầm để đi về điều này. Bạn không nhận được bất kỳ hỗ trợ thời gian biên dịch nào, nó dễ dàng bị phá vỡ hoặc tấn công thông qua việc sử dụng trình giải mã, và người dùng của lớp giờ đây có một phương thức API khó hiểu để xem chúng không thực sự sử dụng. – Servy

+0

Câu hỏi là: "Tôi muốn một phương thức cụ thể trong một lớp chỉ có thể truy cập được bởi một lớp cụ thể." Bạn chỉ cần không cố gắng làm điều đó ... Điều khác là khai báo một phương thức bên trong và sau đó truy cập nó từ tất cả các lớp trong assembly. Nhưng đó không phải là câu hỏi. –

+0

Và điều này không giải quyết được vấn đề đó; phương pháp vẫn có thể truy cập được ở khắp mọi nơi, nó sẽ không hoạt động đúng nếu được sử dụng ở bất cứ đâu mà không có đối số phép thuật chính xác. Cả hai giải pháp của Jon đều liên quan đến việc hạn chế khả năng truy cập của phương thức từ những phương thức không cần truy cập. – Servy

2

Giả sử bạn chỉ muốn hạn chế quyền truy cập vào các phương thức và biến cho một ví dụ cụ thể, bạn có thể đạt được hiệu ứng này bằng cách sử dụng giao diện. Tuy nhiên, nó không ngăn cản ai đó tạo ra thể hiện riêng của họ về lớp, tại thời điểm đó họ sẽ có toàn quyền truy cập vào cá thể đó.

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

Có thể đây là giải pháp thay thế.

Sử dụng System.Runtime.CompilerServices và sau đó bạn có thể kiểm tra Tên của chức năng gọi và/hoặc tệp, trong đó chức năng gọi được xác định. Nếu bạn có một lớp cho mỗi tệp, tên tệp có thể là một trạm biến áp cho tên lớp. Kiểm tra và chặn cuộc gọi.

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 
} 
Các vấn đề liên quan