2012-05-24 56 views
6

Nếu tôi muốn một hàm tạo chỉ có thể truy cập từ các lớp con tôi có thể sử dụng từ khóa protected trong hàm tạo.Làm cách nào để tạo một hàm tạo chỉ có thể truy cập bởi lớp cơ sở?

Bây giờ tôi muốn điều ngược lại.

Lớp con tôi phải có một hàm tạo có thể truy cập được bởi lớp cơ sở của nó nhưng không phải từ bất kỳ lớp nào khác.

Điều này có thể thực hiện được không?

Đây là mã hiện tại của tôi. vấn đề là các lớp con có một hàm tạo công khai.

public abstract class BaseClass 
{ 
    public static BaseClass CreateInstance(DataTable dataTable) 
    { 
     return new Child1(dataTable); 
    } 
    public static BaseClass CreateInstance(DataSet dataSet) 
    { 
     return new Child2(dataSet); 
    } 
} 

public class Child1 : BaseClass 
{ 
    public Child1(DataTable dataTable) 
    { 
    } 
} 

public class Child2 : BaseClass 
{ 
    public Child2(DataSet dataSet) 
    { 
    } 
} 
+4

Tôi không chắc chắn điều này là có thể, một lớp cơ sở biết về các lớp học trẻ em chống lại sự hiểu biết của tôi về thừa kế –

+1

@DanF Bạn nói đúng, nhưng một lớp 'BaseClassFactory' không biết về' Child1' và ' Child2' sẽ là bình thường, và sẽ có cùng một vấn đề. – hvd

Trả lời

3

trả lời cho câu hỏi là "KHÔNG"

Không có những điều như vậy tồn tại trong OOP cho phép constructor lớp con để chỉ hiển thị cho các lớp cơ sở của nó ...

+0

@Jon - tùy chọn của nó nhưng không giải pháp trong kế thừa đa cấp ... xem xét trường hợp đó .. –

12

tôi nghĩ rằng bạn có hai tùy chọn:

  1. Làm cho trình tạo con internal. Điều này có nghĩa là nó sẽ có thể truy cập từ tất cả các loại trong cùng một assembly, nhưng điều đó là đủ trong hầu hết các trường hợp.
  2. Làm cho lớp con lồng nhau trong lớp cơ sở:

    public abstract class BaseClass 
    { 
        public static BaseClass CreateInstance(DataTable dataTable) 
        { 
         return new Child1(dataTable); 
        } 
    
        private Child1 : BaseClass 
        { 
         public Child1(DataTable dataTable) 
         { 
         } 
        } 
    } 
    

    Bằng cách này, BaseClass có thể sử dụng các nhà xây dựng, nhưng không có loại bên ngoài khác có thể làm điều đó (hoặc thậm chí nhìn thấy lớp trẻ).

+3

+1 Đối với các lớp lồng nhau –

+2

các lớp lồng nhau sẽ chỉ hiển thị bên trong BaseClass, phải không? Không chắc chắn đây là những gì được dự định. –

+0

@lcfseth, vâng, nếu bạn đánh dấu chúng là 'riêng tư'. Và tôi nghĩ rằng đây là chính xác những gì đã được dự định (chú ý rằng các phương thức factory trả về 'BaseClass'). – svick

-1

Như Pranay Rana nói, điều này là không thể. Nếu bạn có thể giải thích rõ ràng tại sao bạn muốn điều này, và tại sao không có kỹ thuật khác là có thể, sau đó có thể Microsoft C# designteam sẵn sàng thêm điều này trong một phiên bản tương lai của C#.

Tuy nhiên, ngôn ngữ C# (và nhiều ngôn ngữ OO khác đã tồn tại trong nhiều năm mà không cần khả năng này.

+0

Tôi không thấy làm thế nào là nói về một phiên bản tương lai có thể có của C# hữu ích ở đây. – svick

3

Tôi nghĩ rằng tôi chỉ giải quyết nó bằng bản thân mình. Sau khi đọc svicks giải pháp với các lớp lồng nhau, tôi nghĩ why not use an protected nested class as an argument?

Không ai từ bên ngoài có thể tạo ra một thể hiện của Arg và contructors nào từ các lớp con tôi chỉ có thể được sử dụng bởi BaseClass mà có thể tạo Arg<T> trường.

public abstract class BaseClass 
{ 
    protected class Arg<T> 
    { 
     public T Value { get; set; } 
     public Arg(T value) { this.Value = value; } 
    } 

    public static BaseClass CreateInstance(DataTable dataTable) 
    { 
     return new Child1(new Arg<DataTable>(dataTable)); 
    } 

    public static BaseClass CreateInstance(DataSet dataSet) 
    { 
     return new Child2(new Arg<DataSet>(dataSet)); 
    } 
} 


public class Child1 : BaseClass 
{ 
    public Child1(Arg<DataTable> arg) : this(arg.Value) { } 
    private Child1(DataTable dataTable) 
    { 
    } 
} 

public class Child2 : BaseClass 
{ 
    public Child2(Arg<DataSet> arg) : this(arg.Value) { } 
    public Child2(DataSet dataSet) 
    { 
    } 
} 
+1

Làm thế nào để bảo vệ chống lại 'Child2' instantiating một' Child1'? Tôi nghĩ rằng bạn muốn bảo vệ chính mình ngay cả chống lại những sự nhầm lẫn sai trong hội đồng của riêng bạn? (Nếu không, giải pháp của một hàm tạo bên trong đơn giản hơn nhiều.) – hvd

+0

Thực ra, C# thậm chí cho phép một kiểu không truy cập được trên một hàm tạo công khai? – hvd

+0

Bạn nói đúng. Điều này mang lại cho tôi một lỗi thời gian biên dịch. –

0

Người ta có thể thực thi các hành vi mong muốn tại thời gian chạy bằng cách có các nhà xây dựng cơ sở chấp nhận một tham số ref, và làm điều gì đó tương tự (không threadsafe):

private int myMagicCounter; 

public DerivedClass makeDerived(whatever) // A factory method 
{ 
    DerivedClass newThing; 
    try 
    { 
    ... do whatever preparation 
    newThing = new DerivedClass(ref myMagicCounter, whatever); 
    } 
    finally 
    { 
    ... do whatever cleanup 
    } 
    return newThing; 
} 

BaseClass(ref int magicCounter, whatever...) 
{ 
    if (magicCounter != myMagicCounter) 
    throw new InvalidOperationException(); 
    myMagicCounter++; 
    if (magicCounter != myMagicCounter) 
    throw new InvalidOperationException(); 
} 

Lưu ý rằng nó sẽ không thể cho một cuộc gọi constructor lớp được thừa kế để có được quyền kiểm soát mà không cần chuẩn bị phương pháp của nhà máy, hoặc để trả lại quyền kiểm soát cho người gọi mà không cần dọn dẹp phương thức của nhà máy. Tuy nhiên, sẽ không có gì để ngăn cản hàm tạo lớp dẫn xuất từ ​​truyền thể hiện được xây dựng một phần của nó sang mã bên ngoài mà có thể làm bất cứ điều gì nó thích với nó trong một khoảng thời gian tùy ý trước khi trở về kiểm soát phương thức của nhà máy.

Các vấn đề liên quan