Làm thế nào tôi nên cung cấp thêm thông tin về một ngoại lệ?


20

Mỗi lần tôi cần phải cung cấp thêm thông tin về một ngoại lệ Tôi ngạc nhiên mà cách thực sự là đúng cách để làm điều này.


Vì lợi ích của câu hỏi này, tôi đã viết một ví dụ. Giả sử có một lớp nơi chúng tôi muốn cập nhật Abbreviationtài sản. Từ quan điểm RẮN, nó có thể không hoàn hảo nhưng ngay cả khi chúng ta đã truyền phương thức worker qua DI với một số dịch vụ thì tình huống tương tự sẽ xảy ra - một ngoại lệ xảy ra không có bối cảnh nào. Quay lại ví dụ ...

class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Abbreviation { get; set; }
}

Sau đó, có một số trường hợp của lớp và một vòng lặp trong đó phương thức worker được gọi. Nó có thể ném StringTooShortException.

var persons =
{
    new Person { Id = 1, Name = "Fo" },
    new Person { Id = 2, Name = "Barbaz" },
}

public IEnumerable<Person> GenerateAbbreviation(IEnumerable<Person> persons)
{
    foreach (var person in persons)
    {
        try
        {
            person.Abbreviation = GenerateAbbreviation(person.Name);
        }
        catch(Exception ex)
        {
            // ?
        }
    }
    // throw AggregateException...
}

public IEnumerable<string> GenerateAbbreviation(string value)
{
    if (value.Length < 5)
    {
        throw new StringTooShortException(value);
    }

    // generate abbreviation
}

Câu hỏi là: làm thế nào để thêm Personhoặc của nó Id(hoặc bất cứ điều gì khác)?


Tôi biết ba kỹ thuật sau:


1 - Sử dụng Datatài sản

Ưu điểm:

  • dễ dàng thiết lập thông tin bổ sung
  • không yêu cầu tạo ra nhiều ngoại lệ hơn
  • không yêu cầu thêm try/catch

Nhược điểm:

  • không thể dễ dàng tích hợp vào Message
  • loggers bỏ qua lĩnh vực này và sẽ không bỏ nó
  • yêu cầu khóa và đúc giá trị becasue là object
  • không bất biến

Thí dụ:

public IEnumerable<Person> GenerateAbbreviation(IEnumerable<Person> persons)
{
    foreach (var person in persons)
    {
        try
        {
            person.Abbreviation = GenerateAbbreviation(person.Name);
        }
        catch(Exception ex)
        {
            ex.Data["PersonId"] = person.Id;
            // collect ex
        }
    }
    // throw AggregateException...
}

2 - Sử dụng thuộc tính tùy chỉnh

Ưu điểm:

  • tương tự như Datatài sản nhưng đánh máy mạnh
  • dễ dàng tích hợp vào Message

Nhược điểm:

  • yêu cầu ngoại lệ tùy chỉnh
  • logger sẽ bỏ qua chúng
  • không bất biến

Thí dụ:

public IEnumerable<Person> GenerateAbbreviation(IEnumerable<Person> persons)
{
    foreach (var person in persons)
    {
        try
        {
            person.Abbreviation = GenerateAbbreviation(person.Name);
        }
        catch(Exception ex)
        {
            // not suitable for this exception because 
            // it doesn't have anything in common with the Person
        }
    }
    // throw AggregateException...
}

3 - Bao bọc ngoại lệ với một ngoại lệ khác

Ưu điểm:

  • Message có thể được định dạng theo một cách có thể dự đoán
  • loggers sẽ bỏ các ngoại lệ bên trong
  • bất biến

Nhược điểm:

  • yêu cầu bổ sung try/catch
  • bao gồm làm tổ
  • tăng độ sâu của các ngoại lệ

Thí dụ:

public IEnumerable<Person> GenerateAbbreviation(IEnumerable<Person> persons)
{
    foreach (var person in persons)
    {
        try
        {
            try
            {
                person.Abbreviation = GenerateAbbreviation(person.Name);
            }
            catch(Exception ex)
            {
                throw new InvalidPersonDataException(person.Id, ex);
            }
        }
        catch(Exception ex)
        {
            // collect ex
        }
    }
    // throw AggregateException...
}

  • Có bất kỳ mô hình khác?
  • Có mô hình tốt hơn?
  • Bạn có thể đề xuất thực hành tốt nhất cho bất kỳ / tất cả trong số họ?

Không quen thuộc với các ngoại lệ trong C # nhưng tôi thường mong muốn cá thể Person vẫn còn hiệu lực khi ném ngoại lệ. Bạn đã thử chưa?
John Kouraklis

1
@JohnKouraklis đây không phải là câu hỏi về cái gì ;-) Đây chỉ là một ví dụ cực kỳ đơn giản để chứng minh những gì tôi muốn nói qua thông tin bổ sung. Nếu tôi đăng ở đây toàn bộ khuôn khổ nơi các phương thức của người đột biến có thể đưa ra các ngoại lệ và mức độ thông tin bối cảnh sẽ được cung cấp thì không ai có thể đọc được điều này và tôi đã rất khó để giải thích nó.
t3chb0t

@JohnKouraklis Tôi vừa mới làm nó cho mục đích trình diễn.
t3chb0t

@ t3chb0t Tôi nghĩ bạn đã trả lời câu hỏi của riêng bạn ở đây. Cân nhắc chuyển 1, 2, & 3 thành câu trả lời và điều chỉnh câu hỏi của bạn để không yêu cầu tôi chọn kiểu dựa trên ý kiến ​​của mình.
candied_orange

Có gì sai với ngoại lệ tùy chỉnh? Hoàn thành đúng cách, chúng là một phần của ngôn ngữ miền của bạn và giúp đạt được sự trừu tượng khỏi các chi tiết triển khai.
RubberDuck

Câu trả lời:


6

Data FTW .

"Contra" của bạn:

  • "không thể dễ dàng tích hợp vào Tin nhắn"

-> Đối với các loại ngoại lệ của bạn , nó sẽ đủ dễ dàng để ghi đèMessage để nó không Kết hợp Data.. mặc dù tôi sẽ chỉ xem xét việc này nếu Datalà thông điệp .

  • "loggers bỏ qua lĩnh vực này và sẽ không đổ nó"

Googling cho Nlog là một ví dụ mang lại :

Trình kết xuất bố cục ngoại lệ

(...)

định dạng - Định dạng của đầu ra. Phải là một danh sách bằng dấu phẩy của các thuộc tính ngoại lệ: Message, Type, ShortType, ToString, Method, StackTrace&Data . Giá trị tham số này không phân biệt chữ hoa chữ thường. Mặc định:message

Vì vậy, có vẻ như đó là cấu hình dễ dàng.

  • yêu cầu khóa và truyền vì các giá trị là đối tượng

Huh? Chỉ cần đổ các đối tượng trong đó và đảm bảo rằng chúng có thể sử dụng đượcToString() phương thức .

Ngoài ra, tôi không thấy bất kỳ vấn đề nào với các phím. Chỉ cần sử dụng một số tính độc đáo nhẹ và bạn đã tốt.


Tuyên bố miễn trừ trách nhiệm: Đây là những gì tôi có thể thấy ngay từ câu hỏi và những gì tôi đã hiểu được Datatrong 15 phút. Tôi nghĩ rằng nó rất hữu ích, vì vậy tôi đưa ra câu trả lời, nhưng tôi chưa bao giờ sử dụng Databản thân mình, vì vậy có lẽ người hỏi ở đây biết nhiều về vấn đề này hơn tôi.


Tôi đi đến kết luận rằng chỉ có hai điều về một ngoại lệ hữu ích, đó là tên và thông điệp của nó. Mọi thứ khác chỉ là tiếng ồn vô dụng có thể và nên được bỏ qua vì đơn giản là nó quá mỏng manh dựa vào nó.
t3chb0t

2

Tại sao bạn ném Ngoại lệ? Để họ bị bắt và xử lý.

Làm thế nào để mã bắt làm việc ra làm thế nào để xử lý Ngoại lệ? Sử dụng các thuộc tính mà bạn xác định trên đối tượng Ngoại lệ.

Không bao giờ sử dụng thuộc tính Message để xác định ngoại lệ, cũng như không cung cấp "thông tin" mà bất kỳ trình xử lý tiềm năng nào cũng nên dựa vào. Nó đơn giản là quá dễ bay hơi và không đáng tin cậy.

Tôi chưa bao giờ sử dụng thuộc tính "Dữ liệu" trước đây nhưng nó có vẻ quá chung chung với tôi.

Trừ khi bạn tạo nhiều lớp Ngoại lệ, mỗi lớp xác định một trường hợp ngoại lệ cụ thể , làm sao bạn biết khi bạn bắt Ngoại lệ, "Dữ liệu" đại diện cho điều gì? (Xem bình luận trước về "Tin nhắn").


1
Tôi nói, Datalà vô ích để xử lý, nhưng có giá trị để đăng nhập để tránh Messageđịnh dạng địa ngục.
Martin Ba

-1

Tôi thích ví dụ thứ ba của bạn, tuy nhiên có một cách khác nó có thể được mã hóa để loại bỏ hầu hết các "con" của bạn.

public IEnumerable<Person> GenerateAbbreviation(IEnumerable<Person> persons)
{
    var exceptions = new List<InvalidPersonDataException>();

    foreach (var person in persons)
    {
        try
        {
            person.Abbreviation = GenerateAbbreviation(person.Name);
        }
        catch(Exception ex)
        {
            exceptions.Add(new InvalidPersonDataException(person.Id, ex));
        }
    }

    if (exceptions.Any())
    {
        throw new AggregateException(exceptions);
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.