2010-06-18 70 views
5

Tôi nhầm lẫn là tại sao toán tử new không hoạt động như tôi mong đợi.Toán tử mới trong C# không ghi đè thành viên lớp cơ sở

Lưu ý: Tất cả các lớp bên dưới được xác định trong cùng một không gian tên và trong cùng một tệp.

Lớp này cho phép bạn thêm tiền tố vào bất kỳ nội dung nào được ghi vào bảng điều khiển với một số văn bản được cung cấp.

public class ConsoleWriter 
{ 
    private string prefix; 

    public ConsoleWriter(string prefix) 
    { 
     this.prefix = prefix; 
    } 

    public void Write(string text) 
    { 
     Console.WriteLine(String.Concat(prefix,text)); 
    } 
} 

Đây là một lớp cơ sở:

public class BaseClass 
{ 
    protected static ConsoleWriter consoleWriter = new ConsoleWriter(""); 

    public static void Write(string text) 
    { 
     consoleWriter.Write(text); 
    } 
} 

Dưới đây là một lớp thực hiện:

public class NewClass : BaseClass 
{ 
    protected new static ConsoleWriter consoleWriter = new ConsoleWriter("> "); 
} 

Bây giờ đây là mã để thực hiện điều này:

class Program 
{ 
    static void Main(string[] args) 
    { 
     BaseClass.Write("Hello World!"); 
     NewClass.Write("Hello World!"); 

     Console.Read(); 
    } 
} 

Vì vậy, tôi mong đợi đầu ra là

Hello World! 
> Hello World! 

Nhưng đầu ra là

Hello World! 
Hello World! 

Tôi không hiểu tại sao điều này đang xảy ra. Đây là quá trình suy nghĩ của tôi về những gì đang xảy ra:

  1. Các CLR gọi BaseClass.Write() phương pháp
  2. Các CLR initialises các BaseClass.consoleWriter thành viên.
  3. Phương pháp này được gọi và thực hiện với các BaseClass.consoleWriter biến

Sau đó

  1. Các CLR gọi NewClass.Write()
  2. Các CLR initialises đối tượng NewClass.consoleWriter.
  3. Các CLR thấy rằng việc thực hiện nằm trong BaseClass, nhưng phương pháp này là thừa hưởng qua
  4. Các CLR thực hiện phương pháp này tại địa phương (trong NewClass) sử dụng NewClass.consoleWriter biến

Tôi nghĩ đây là cách cấu trúc thừa kế công trinh?

Xin vui lòng ai đó có thể giúp tôi hiểu tại sao điều này không hoạt động?

-

Cập nhật:

Kịch bản này sẽ làm việc như sau (làm thế nào tôi đã thực hiện nó)

public class LogBase 
{ 
    protected static TraceSource logger = new TraceSource(""); 

    public static void Error (string text) { logger.WriteError(text); } 
    public static void Info (string text) { logger.WriteInformation(text); } 
    public static void Warning (string text) { logger.WriteWarning(text); } 
    public static void Verbose (string text) { logger.WriteVerbose(text); } 
} 

// DataAccess logging 
public class DALog : LogBase 
{ 
    protected new static TraceSource logger = new TraceSource("DataAccess"); 
} 

// BusinessObjects logging 
public class BOLog : LogBase 
{ 
    protected new static TraceSource logger = new TraceSource("Objects"); 
} 

// BusinessLogic logging 
public class BLLog : LogBase 
{ 
    protected new static TraceSource logger = new TraceSource("Logic"); 
} 

// WebUI logging 
public class WebUILog : LogBase 
{ 
    protected new static TraceSource logger = new TraceSource("WebUI"); 
} 

Lý do là tôi không cần phải lặp lại mã cho mọi lớp học.

-

Cập nhật (sau khi giải pháp được lựa chọn):

Vì vậy, để có được xung quanh vấn đề này, thay vì sử dụng các lớp cơ sở, tôi đã xác định các chức năng một. Sau đó, tạo các lớp học mới, tổ chức các cá thể Singleton cho mỗi lớp:

public sealed class LogBase 
{ 
    private TraceSource logger = null; 

    public static LogBase GetLogger(string loggerName) 
    { 
     return new LogBase(loggerName); 
    } 

    private LogBase(string loggerName) { logger = new TraceSource(loggerName); } 

    public void Error (string text) { logger.WriteError(text); } 
    public void Info (string text) { logger.WriteInformation(text); } 
    public void Warning (string text) { logger.WriteWarning(text); } 
    public void Verbose (string text) { logger.WriteVerbose(text); } 
} 

// DataAccess logging - no base class 
public class DALog 
{ 
    private static LogBase logger; 

    public static LogBase Instance 
    { 
     get 
     { 
       if (logger==null) { logger = new TraceSource("DataAccess"); } 
       return logger; 
     } 
    } 
} 

... 

Trả lời

8

Toán tử đa hình không thực sự ghi đè theo nghĩa đa hình. Nó chỉ thêm một phương thức khác "xảy ra" để có cùng chữ ký và được coi là một phương thức riêng biệt. Chỉ khi bạn thực hiện phương thức đó một cách rõ ràng trên lớp con, triển khai "mới" sẽ được sử dụng.

Trong trường hợp của bạn, bạn đã triển khai Write chỉ trên lớp cơ sở. Trong đó, bạn có dòng gọi consoleWriter. Dòng đó đề cập đến lớp cơ sở và do đó sử dụng triển khai ban đầu. Nó thậm chí không biết về việc thực hiện bổ sung trong lớp con.

xét mã và về vấn đề đó của bạn vì nó sẽ là:

public class BaseClass 
{ 
    protected static ConsoleWriter consoleWriter = new ConsoleWriter(""); 

    public static void Write(string text) 
    { 
     consoleWriter.Write(text); 
    } 
} 


public class NewClass : BaseClass 
{ 
    protected static ConsoleWriter anotherConsoleWriter = new ConsoleWriter(">"); 
} 

BaseClass.Write của bạn sẽ không bao giờ xem xét để gọi anotherConsoleWriter thay vì consoleWriter.

Nếu bạn muốn ví dụ của bạn để làm việc, bạn có cần phải thêm một thực hiện mới cho Write:

public class NewClass : BaseClass 
{ 
    protected new static ConsoleWriter consoleWriter = new ConsoleWriter(">"); 

    public static new void Write(string text) 
    { 
     consoleWriter.Write(text); 
    } 
} 

... hay, những gì bạn có lẽ hầu hết ban đầu muốn, chứ không phải giới thiệu thực trọng trong ý nghĩa của đa hình bằng cách sử dụng override thay vì new. Tuy nhiên, lớp cơ sở của bạn cần hỗ trợ điều đó bằng cách tuyên bố consoleWriter là virtual. Hơn nữa (như bạn đã đề cập trong bình luận của bạn) điều này chỉ hoạt động nếu bạn không làm cho các phương pháp này tĩnh.

Bạn có thể áp dụng Singleton pattern thay vào đó nếu bạn vẫn muốn truy cập tĩnh vào nhật ký của mình hoặc xem log4net đã giải quyết tất cả các sự cố này cho bạn.

+0

Tôi không thể khai báo các phương thức tĩnh là ảo. Có lẽ tôi nên trả về một thể hiện của lớp và sau đó gọi các phương thức không tĩnh để giải quyết vấn đề này? –

+0

Có, hãy làm điều đó. Bạn có thể làm cho nó một singleton và vẫn cung cấp một cách tĩnh để truy cập nó như: LogBase.GetLogger ("DataAccess"). Và sau đó bạn gần như trông như thế nào trong log4net, mà bạn có thể muốn xem. – chiccodoro

2

Thiếu một vài điểm quan trọng của bạn .. Tĩnh làm cho nó là một trường cấp lớp. Được bảo vệ có nghĩa là nó có sẵn từ các lớp dẫn xuất. Mới có nghĩa là bạn đang ẩn thành viên cơ sở.

Bạn có cần các lớp này là tĩnh không? Nếu không, bạn có thể làm cho phương thức Write ảo và ghi đè nó trong lớp dẫn xuất; base.Write (">" + văn bản);

+0

Tôi muốn nó tĩnh vì tôi có thể định nghĩa tất cả các phương thức của tôi trong một lớp cơ sở, mà lần lượt gọi một thành viên tĩnh (trong thực thi thực tế nó là một TraceSource). Do đó, điều duy nhất tôi phải thay đổi liên quan đến các lớp cơ sở kế thừa của tôi là việc triển khai được ghi đè. Tôi sẽ cập nhật câu hỏi. –

1

Bạn biết rằng kế thừa và ghi đè tác phẩm cho các phương thức thể hiện (ảo), không phải là phương thức tĩnh, đúng không?

Ghi đè của bạn là protected và do đó không hiển thị bên ngoài NewClass và hậu duệ của bạn. Do đó, hành vi là do spec. new chỉ cho phép bạn tạo một hàm mới có thể được tham chiếu bởi cùng một mã định danh trong ngữ cảnh của nó: phương pháp NewClass.Write của bạn thực sự không liên quan gì đến số BaseClass.Write của bạn.

+0

Cảm ơn Pontus. Tất cả các từ khóa đã được chọn cho một mục đích cụ thể, tuy nhiên bây giờ tôi hiểu rằng chúng không chính xác. Đây là lý do: 'được bảo vệ' là vì tôi chỉ muốn các lớp con để xem thành viên, để ghi đè lên nó. 'mới' vì tôi muốn phương pháp sử dụng phiên bản ghi đè. Và 'tĩnh' là thành viên đã được sử dụng cùng với các phương pháp tĩnh (để thuận tiện thực sự, thay vì tôi phải 'mới' nó lên mỗi lần). Nhưng như chúng ta đã thấy ở đây, các thành viên và phương pháp tĩnh KHÔNG được kế thừa. –

3

Câu hỏi ban đầu đã được trả lời bởi người khác: hành vi mà OP mong đợi là những gì bạn nhận được từ việc ghi đè phương pháp, chứ không phải những gì bạn nhận được từ việc sử dụng new.

Trong câu trả lời của OP, anh lo ngại rằng bạn không thể ghi đè phương pháp tĩnh. Đó là sự thật, nhưng đây là một blog từ msdn mà cả hai đều giải thích tại sao và thảo luận về cách xử lý nó: http://blogs.msdn.com/b/kirillosenkov/archive/2008/02/06/how-to-override-static-methods.aspx

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