2010-05-24 40 views
9

Tôi muốn làm như sauThiết kế lớp C# - tôi có thể sử dụng gì thay vì "tóm tắt tĩnh"? không

public abstract class MyAbstractClass 
{ 
    public static abstract int MagicId 
    { 
     get; 
    } 

    public static void DoSomeMagic() 
    { 
     // Need to get the MagicId value defined in the concrete implementation 
    } 
} 

public class MyConcreteClass : MyAbstractClass 
{ 
    public static override int MagicId 
    { 
     get { return 123; } 
    } 
} 

Tuy nhiên tôi có thể vì bạn can't have static abstract members.

Tôi hiểu tại sao tôi không thể làm điều này - bất kỳ đề xuất nào cho một thiết kế sẽ đạt được nhiều kết quả tương tự?

(Để rõ ràng - Tôi cố gắng để cung cấp một thư viện với một lớp cơ sở trừu tượng nhưng các phiên bản bê tông PHẢI thực hiện một thuộc tính vài/phương pháp bản thân và có, có những lý do tốt để giữ cho nó tĩnh.)

+4

Tôi tự hỏi "lý do chính đáng" là gì - vì chúng có thể ảnh hưởng đến cách tốt nhất để tiếp tục từ đây. –

+0

Bạn có thể chia sẻ các lý do * tốt * để có thuộc tính này 'tĩnh' để chúng tôi có thể hiểu rõ hơn về kịch bản của bạn và đề xuất các giải pháp. Ngay bây giờ nó không rõ ràng những gì bạn đang cố gắng để đạt được. –

+0

Nó thực sự phụ thuộc vào những gì bạn đang cố gắng làm. – bitbonk

Trả lời

4

Mẫu Singleton có hoạt động không? Một liên kết đến bài viết MSDN mô tả làm thế nào để thực hiện một singleton trong C#:

http://msdn.microsoft.com/en-us/library/ff650316.aspx

Trong ví dụ cụ thể của bạn, trường hợp Singelton có thể mở rộng một lớp cơ sở trừu tượng với MagicId của bạn trong đó.

Chỉ cần suy nghĩ :)

5

Bạn về cơ bản là không thể làm cho DoSomeMagic() hoạt động với thiết kế hiện tại. Cuộc gọi đến số MyConcreteClass.DoSomeMagic trong mã nguồn sẽ được dịch sang số MyAbstractClasss.DoSomeMagic trong IL. Thực tế là ban đầu nó được gọi là sử dụng MyConcreteClass bị mất.

Bạn có thể xem xét có một phân cấp lớp song song có cùng phương thức nhưng ảo - sau đó kết hợp từng thể hiện của lớp gốc với một thể hiện của lớp chứa các thành viên trước đó tĩnh ... và có lẽ chỉ có một ví dụ của mỗi người trong số đó.

+0

Có, tôi hiểu tại sao tôi không thể làm như vậy - câu hỏi của tôi là whats thiết kế chính xác. – Ryan

+2

@Ryan: Đó là lý do tại sao tôi cũng bao gồm đoạn thứ hai :) –

0

Không phải là một fan hâm mộ lớn của tùy chọn này nhưng ...

Bạn có thể kê khai tài sản tĩnh, không trừu tượng, ảo và ném một NotImplementedException mà trả về một thông báo lỗi rằng phương pháp này phải được ghi đè trong một lớp học có nguồn gốc .

Bạn di chuyển lỗi từ thời gian biên dịch sang thời gian chạy mặc dù có vẻ xấu xí.

+0

Bạn không thể ghi đè thành viên tĩnh. – zneak

+0

Bah oops. Tôi muốn downvote bản thân mình nếu tôi có thể – JoshReedSchramm

2

lựa chọn tốt nhất của bạn là sử dụng một giao diện với MagicId chỉ sử dụng một setter

public interface IMagic 
{ 
    int MagicId { get; } 
} 

Bởi bản chất của ý nghĩa tĩnh chỉ có thể có một (vâng như Highlander), bạn không thể ghi đè lên chúng.

Sử dụng giao diện giả định khách hàng của bạn sẽ triển khai hợp đồng. Nếu họ muốn có một thể hiện cho mỗi hoặc trả về giá trị của một biến tĩnh, nó tùy thuộc vào chúng.

Lý do chính đáng để giữ mọi thứ tĩnh cũng có nghĩa là bạn KHÔNG cần phải ghi đè lên lớp con.

+2

+1 cho Highlander nhận xét – statenjason

+0

Làm thế nào để sử dụng giao diện giúp tôi có được nhiều hơn trừu tượng không tĩnh? Trong thực tế nó tồi tệ hơn như trình biên dịch không lực lượng lớp bê tông để thực hiện giao diện. http://stackoverflow.com/questions/510341/force-subclasses-of-an-interface-to-implement-tostring-c – Ryan

0

Ngôn ngữ thực hiện kế thừa các thành viên tĩnh thực hiện thông qua metaclasses (có nghĩa là, các lớp cũng là đối tượng và các đối tượng này có metaclass và thừa kế tĩnh tồn tại thông qua nó). Bạn có thể vaguely transpose rằng để các mô hình nhà máy: một lớp học có các thành viên ma thuật và có thể tạo ra các đối tượng của lớp thứ hai.

Điều đó hoặc sử dụng phản chiếu. Nhưng bạn không thể đảm bảo tại thời gian biên dịch mà một lớp dẫn xuất thực hiện tĩnh một thuộc tính nhất định.

0

Tại sao không chỉ biến nó thành thành viên không tĩnh?

+0

Thành viên nào - hoặc tất cả chúng? – Ryan

3

Tôi sẽ đặt câu hỏi rằng có "lý do chính đáng" để làm cho các thành viên trừu tượng tĩnh.

Nếu suy nghĩ của bạn là các thành viên này có thể phản ánh một số thuộc tính của lớp dẫn xuất chứ không phải là một cá thể cụ thể, điều này không nhất thiết có nghĩa là các thành viên nên tĩnh.

Xem xét thuộc tính IList.IsFixedSize. Đây thực sự là tài sản của loại của IList, không phải bất kỳ trường hợp cụ thể nào (tức là, bất kỳ T[] nào sẽ có kích thước cố định; nó sẽ không thay đổi từ T[] sang loại khác). Nhưng nó vẫn là một thành viên thể hiện. Tại sao? Bởi vì kể từ nhiều loại có thể triển khai IList, nó sẽ thay đổi từ một IList khác.

Hãy xem xét một số mã có bất kỳ MyAbstractClass (từ ví dụ của bạn). Nếu mã này được thiết kế đúng cách, trong hầu hết các trường hợp, nó không nên quan tâm đến lớp dẫn xuất mà nó thực sự đang xử lý. Điều quan trọng là bất cứ điều gì MyAbstractClass phơi bày. Nếu bạn thực hiện một số thành viên trừu tượng tĩnh, về cơ bản, cách duy nhất để truy cập chúng sẽ là như sau:

int magicId; 
if (concreteObject is MyConcreteClass) { 
    magicId = MyConcreteClass.MagicId; 
} else if (concreteObject is MyOtherConcreteClass) { 
    magicId = MyOtherConcreteClass.MagicId; 
} 

Tại sao một mớ hỗn độn như vậy? Điều này tốt hơn nhiều, đúng không?

int magicId = concreteObject.MagicId; 

Nhưng có lẽ bạn có lý do chính đáng khác chưa xảy ra với tôi.

0

Các provider pattern, được sử dụng bởi các nhà cung cấp thành viên ASP.NET, ví dụ, có thể là những gì bạn đang tìm kiếm.

Bạn không thể có hành vi đa hình trên các thành viên tĩnh, vì vậy bạn sẽ có một lớp tĩnh mà các thành viên đại diện cho một trường giao diện (hoặc lớp trừu tượng) sẽ đóng gói các hành vi đa hình.

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