2010-03-07 40 views
5

Tôi đang làm việc trên một phần nhận xét công khai của một ứng dụng vào thứ Sáu khi tôi gặp lỗi tràn ngăn xếp, điều này làm tôi bối rối nên tôi nghĩ tôi sẽ yêu cầu trợ giúp. Và tìm kiếm trên web bằng cách sử dụng cụm từ 'chồng tràn' là một chút tự đánh bại!Lỗi tràn ngăn xếp trong C# set/get

tôi muốn làm một HtmlEncode trên báo cáo kết quả tập hợp các lĩnh vực này trong lớp, trước khi gửi một thể hiện của lớp được bổ sung vào cơ sở dữ liệu:

public class Feedback 
{ 

    public Feedback() { } 

    public string FeedbackComment 
    { 
     get { return FeedbackComment; } 
     set {System.Web.HttpUtility.HtmlEncode(value); } 
    } 

    // other fields 

    // methods 
} 

này đã gây ra StackOverflow lỗi, tôi đã sửa lỗi bằng cách thay đổi mã để trông như thế này:

public class Feedback 
{ 

    public Feedback() { } 

    private string feedbackComment; 

    public string FeedbackComment 
    { 
     get { return feedbackComment; } 
     set { feedbackComment = System.Web.HttpUtility.HtmlEncode(value); } 
    } 

    // other fields 

    // methods 
} 

nhưng tôi chỉ muốn giải thích về lý do tại sao get/set báo cáo đầu tiên đã rất đệ quy mà họ đã gây ra một chồng tràn nhưng khi quay trở lại các mã nhìn giống như C# 2.0 làm việc? Điều này có thể đạt được với cú pháp ngắn hơn và nếu như vậy làm thế nào?

Đây là câu hỏi đầu tiên của tôi về SO - hãy cố gắng nhẹ nhàng!

+5

Tôi không thể không nghĩ rằng trang web này là địa điểm lý tưởng cho câu hỏi này – jakebman

+0

Rất nhiều câu trả lời đúng - cảm ơn tất cả sự trợ giúp. – amelvin

Trả lời

21

Bộ lấy mẫu của ví dụ đầu tiên sẽ trả về chính thuộc tính chứ không phải trường sao lưu.

// The property name is "FeedbackComment" 
public string FeedbackComment 
{ 
    // And here you are returning "FeedbackComment" which is 
    // creating the stack overflow 
    get { return FeedbackComment; } 
} 

Đáng tiếc là không có cách nào để rút ngắn những gì bạn đã, tự động thực hiện các thuộc tính (ví dụ: public String FeedbackComment { get; set; }) phải có sản phẩm nào getter và setter khối là đúng cú pháp. Không có gì sai với ví dụ thứ hai của bạn - vâng, nó hơi dài nhưng rõ ràng, súc tích và hoàn thành công việc.

+0

+1 Cảm ơn lời khuyên rằng ví dụ thứ hai là một lựa chọn hợp lý. – amelvin

4

Bạn đang gặp phải tình trạng tràn ngăn xếp trong mã đầu tiên vì trình thu thập thuộc tính của bạn đang trả lại chính thuộc tính.

Điều này sẽ làm cho trình thu thập được gọi lại, và một lần nữa cho đến khi chồng của bạn tràn.

2

Mã đã gây ra StackOverflowException không cung cấp trường sao lưu cho thuộc tính, trình truy cập nhận được trả lại thuộc tính chính là nguyên nhân gây tràn ngăn xếp. Ví dụ thứ hai cung cấp một trường sao lưu và trả về nội dung của nó.

2

Có vẻ như bạn đang cố gắng sử dụng tính năng auto-implemented properties được giới thiệu trong C# 3.0, nhưng tạo ra một chút lộn xộn cú pháp.

Trả lại FeedbackComment trong phần truy cập có được của FeedbackComment propery đang tạo vòng lặp tự tham chiếu giữ 'nhận' thuộc tính, vì vậy không có gì ngạc nhiên về tràn ngăn xếp ở đó!

Cú pháp chính xác cho thuộc tính được tự động triển khai như sau. Tuy nhiên, nó không thể thực hiện bất kỳ xử lý nào trong bộ nhận hoặc thiết lập (theo định nghĩa thực sự).

public class Feedback 
{ 
    public Feedback() { } 

    public string FeedbackComment 
    { 
     get; 
     set; 
    } 

    // other fields 

    // methods 
} 

Trong trường hợp của bạn, vì bạn muốn xử lý trên bộ truy cập 'đặt', làm theo cách tiêu chuẩn để sử dụng trường sao lưu là những gì bạn muốn.

8

Tham chiếu getter (như Andrew đã chỉ ra) nhưng trình thiết lập cũng sai.

Mã này:

set { System.Web.HttpUtility.HtmlEncode(value); } 

... không thực sự thiết lập bất cứ điều gì.Phương thức HtmlEncodetrả về giá trị được mã hóa, nó không thực sự thay đổi value.

Một điều bạn nên lưu ý là nếu bạn đang HtmlEncode-đang trên đường vào, bạn cần phải HtmlDecode trên đường ra, nếu không bạn có thể kết thúc bằng nhiều bảng mã (không phải là idempotent). Nếu bạn đang cố gắng để "tự động hóa" các quá trình mã hóa sau đó các lớp bình thường trông giống như sau:

public class Foo 
{ 
    private string bar; 

    public string Bar 
    { 
     get { return HttpUtility.HtmlDecode(bar); } 
     set { bar = HttpUtility.HtmlEncode(value); } 
    } 

    public string SafeBar 
    { 
     get { return bar; } 
    } 
} 

Hoặc bạn có thể đảo ngược logic an toàn/không an toàn, ví dụ:

public string Bar 
{ 
    get { return bar; } 
    set { bar = HttpUtility.HtmlEncode(value); } 
} 

public string UnsafeBar 
{ 
    get { return HttpUtility.HtmlDecode(value); } 
} 

Dù bằng cách nào lớp học của bạn nên làm cho rõ ràng thực tế là nó đang làm một số loại mã hóa, nếu không nếu bạn viết mã như thế này:

Foo foo1 = new Foo(); 
foo1.Bar = "<test>"; 
Foo foo2 = new Foo(); 
foo2.Bar = foo1.Bar; 

... sau đó bạn sẽ bắt đầu thấy một loạt các ký tự thoát xấu xí trong đầu ra của foo2.Bar. Làm cho hợp đồng của lớp bạn rõ ràng, cần thực hiện cả hai mã hóa giải mã hoặc không thực hiện.

+0

+1 Điểm tốt :) –

+0

+1 Tôi ban đầu đã có một Giải mã, nhưng tôi đã bỏ nó ra để đơn giản hóa ví dụ. Tôi đồng ý với tất cả các ý kiến ​​của bạn. – amelvin

1

Tôi nghĩ rằng bạn thiếu hiểu biết cơ bản về các thuộc tính. Một thuộc tính không thể chứa bất kỳ dữ liệu nào, nó chỉ là một cặp của một phương thức getter và một phương thức setter (cũng có các thuộc tính chỉ có các getters hoặc setters). Phương thức getter về cơ bản là một phương thức không có đối số và trả về một giá trị của kiểu thuộc tính, mặt khác, phương thức không có giá trị trả về và một đối số của kiểu thuộc tính được gọi là giá trị. C# ẩn cả hai phương thức này và kết hợp chúng với một thuộc tính và bạn có thể gọi chúng như một trường bình thường.

thực hiện đầu tiên của bạn là tương đương với:

public class Feedback 
{ 
    public string get_FeedbackComment() 
    { 
     return get_FeedbackComment(); 
    } 

    public void set_FeedbackComment(string value) 
    { 
     System.Web.HttpUtility.HtmlEncode(value); 
    } 
} 

Bạn có thể thấy tại nơi đệ quy là gì và ở đâu lỗi của bạn nằm. Ngoài ra, khi bạn nhìn vào setter, bạn sẽ thấy rằng nó không đặt bất cứ thứ gì. Giá trị trả về của HtmlEncode sẽ không được lưu ở bất kỳ đâu. Bạn cần phải cung cấp một trường sao lưu (giống như một phần trong đoạn mã thứ hai của bạn).

Tuy nhiên, có các thuộc tính được tự động triển khai trong C# 3.0 trở lên mà bạn đã khai báo theo cách sau. Cũng cần lưu ý rằng trình biên dịch C# sẽ tạo ra một trường sao lưu tự động, vì vậy về cơ bản cả hai cách đều giống nhau nhưng bạn có thể linh hoạt hơn với đầu tiên bởi vì với các thuộc tính được tự động thực hiện, bạn không thể thêm hành vi phức tạp hơn là cài đặt đơn giản và lấy các giá trị (ít nhất là trong lớp mà bạn khai báo nó, làm cho nó có thể mở được các thuộc tính ảo để mở rộng logic thuộc tính trong các lớp con ..).

public class Feedback 
{ 
    public string FeedbackComment 
    { 
     get; 
     set; 
    } 
} 

Best Regards,
Oliver Hanappi

+0

Ví dụ đã được đơn giản hóa một chút, vì vậy nếu đó là tạo ra các vấn đề khác đó cũng là lỗi của tôi! Một phần của câu hỏi của tôi là tại sao trường sao lưu chỉ được tạo cho mặc định {get; set;} accessors - và có vẻ như câu trả lời là 'by design'. – amelvin

2

Hãy nhớ rằng tài sản này thực sự phương pháp - họ trình biên dịch sẽ chuyển đổi chúng sang T get_Property()set_Property(T value) cuộc gọi - không có lưu trữ (trừ khi sử dụng proprieties tự động, nhưng những gì xảy ra ở đó là trình biên dịch tạo ra một trường sao lưu tự động.Vì vậy, những gì stack overflow ví dụ của bạn trông giống như là:

public class Feedback 
{ 

    public Feedback() { } 

    // Getter 
    public string get_FeedBackComment() { 
     return get_FeedBackComment(); 
    } 
    // Setter 
    public void set_FeedBackComment(string value) { 
     System.Web.HttpUtility.HtmlEncode(value); 
    } 
} 

Vì vậy, bạn nhận được là lời kêu gọi hàm nào đã gọi nó tự mãi mãi, do đó ngăn xếp tràn vì mỗi cuộc gọi là một chồng đẩy. Và thiết lập được gọi là một hàm, nhưng không bao giờ được lưu trữ giá trị của nó ở bất cứ đâu.

+0

+1 Có, trường sao lưu chỉ được tạo cho mặc định {get; set;} hiện đã rõ. – amelvin

1

Đây là một ví dụ tuyệt vời cho việc xây dựng lạm dụng lập trình đệ quy;)

Vấn đề không phải là liên quan đến bất động sản nhưng về giá trị rtreiving chung từ phương pháp bất kỳ như:

 

public int GiveMeValue() 
{ 
    return GiveMeValue(); 
} 

public void SetValue(int value) 
{ 
    SetValue(value); 
} 
 

Dù sao tính DotNet là loại đặc biệt của phương pháp. phải không?

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