每当我需要提供有关异常的其他信息时,我都会想知道哪种方法实际上是正确的方法。
为了这个问题,我写了一个例子。假设有一个我们要更新Abbreviation
属性的类。从SOLID的角度来看,这可能并不完美,但是即使我们通过具有某些服务的DI 传递了工作方法,也会发生相同的情况-发生异常,并且没有上下文。回到示例...
class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Abbreviation { get; set; }
}
然后是该类的一些实例和一个调用worker方法的循环。它可以抛出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
}
问题是:如何添加Person
或其Id
(或其他任何内容)?
我知道以下三种技术:
1-使用Data
物业
优点:
- 易于设置其他信息
- 不需要创建更多的异常
- 不需要额外
try/catch
缺点:
- 无法轻易整合到
Message
- 记录器会忽略此字段,不会将其转储
- 需要键和强制转换,因为值是
object
- 不是一成不变的
例:
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-使用自定义属性
优点:
- 与
Data
属性相似,但类型强 - 更容易集成到
Message
缺点:
- 需要自定义例外
- 记录器将忽略它们
- 不是一成不变的
例:
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-用另一个异常包装异常
优点:
Message
可以以可预测的方式格式化- 记录器将转储内部异常
- 一成不变的
缺点:
- 需要额外的
try/catch
- 增加嵌套
- 增加肽的深度
例:
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...
}
- 还有其他模式吗?
- 有更好的模式吗?
- 您能为所有/所有建议最佳做法吗?