C# 如何设计流畅的界面(用于异常处理)?
我正在回顾代码库的一部分,接下来是异常处理部分,这部分非常混乱。我想换件更优雅的。然后我想,如果我有一个流畅的界面,可以帮助我注册一些例外列表的策略,并让一个例外处理经理为我做其余的事情,这可能不是一个坏主意: 下面是一个它应该如何工作的示例:C# 如何设计流畅的界面(用于异常处理)?,c#,dsl,fluent-interface,C#,Dsl,Fluent Interface,我正在回顾代码库的一部分,接下来是异常处理部分,这部分非常混乱。我想换件更优雅的。然后我想,如果我有一个流畅的界面,可以帮助我注册一些例外列表的策略,并让一个例外处理经理为我做其余的事情,这可能不是一个坏主意: 下面是一个它应该如何工作的示例: For<TException>.RegisterPolicy<TPolicy>(a lambda expression that describes the detail); 披头士1692,请原谅,我将从解决重构异常处理的主要
For<TException>.RegisterPolicy<TPolicy>(a lambda expression that describes the detail);
披头士1692,请原谅,我将从解决重构异常处理的主要问题开始,而不是直接跳到DSL部分 在你的问题中,你说: 我正在回顾代码库的一部分,接下来是异常处理部分,这部分非常混乱。我想换件更优雅的 我想这是你最关心的。因此,我将尝试为您提供一个如何使其更加优雅的指南-实际上,您提供的代码片段不优雅并不是关于它不是DSL或流畅的接口,而是关于设计质量。如果你的设计中有冗余和耦合,那么在冗余和耦合之上创建一个流畅的界面只会让它变得更糟糕 答案很长,我会参考一些代码质量,所以如果您需要进一步的解释,请告诉我。因为在做出这样的决定时涉及到很多变量,比如变更成本、代码所有权等。我将尝试为您提供最干净的解决方案,然后提供一个需要最少努力的解决方案 在这种情况下,最好应用经典设计模式的作者四人帮的建议。这条建议是:封装变化的内容。在您的情况下,故障处理是变化的,变化基于异常类型。我将如何在这里应用它 第一个解决方案-完全重构代码中的气味 我要问的第一个问题是:您是否可以修改引发异常的代码?如果是这样的话,我会尽量不在捕获异常的代码中进行封装,而是在抛出异常的代码中进行封装。这对您来说可能有些奇怪,但这可能会让您避免冗余。事实上,您的代码当前在两个地方耦合到一种类型的异常 第一个地方是抛出异常的位置,您必须知道要抛出哪个异常-非常简单,它可能如下所示:
if(someSituationTakesPlace())
{
throw new ExpType1();
}
else if(someOtherSituationTakesPlace()
{
throw new ExpType2();
}
public class Failure : Exception
{
IFailureHandling _handling;
public Failure(IFailureHandling handling)
{
//we're injecting how the failure should be handled
_handling = handling;
}
//If you need to provide additional info from
//the place where you catch, you can use parameter list of this method
public void Handle()
{
_handling.Perform();
}
}
if(sensorsFailed())
{
throw _failureFactory.CreateForCaseWhenSensorsAreDamaged();
}
try
{
PerformSomeLogic();
}
catch(Failure failure)
{
failure.Handle();
}
if(exp.GetType()==typeof(expType1))
{
if(exp.Message.Include("something went bad"))
{
if(exp.InnerException.Message == "Something inside went bad as well";
{
DoX();
DoY();
}
}
}
else if (exp.GetType()==typeof(expType2))
{
DoZ();
DoV();
}
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessage(message => message.Includes("something went bad"))
.WithInnerException<SomeInnerException>()
.HavingAMessage(innerMessage => innerMessage == "Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessageThatIncludes("something went bad")
.WithInnerException<SomeInnerException>()
.HavingAMessageEqualTo("Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
当然,条件可能更复杂,可能有多个不同的对象和方法可以抛出,但本质上,它总是归结为一系列的选择,比如在情况a中,抛出异常X
有这种映射的第二个地方是当您捕获异常时——您必须再次通过一系列if-else来找出它是什么情况,然后调用一些逻辑来处理它
为了避免这种冗余,我将决定抛出异常的处理方式——您应该在那里拥有所需的所有信息。因此,我首先定义一个异常类,如下所示:
if(someSituationTakesPlace())
{
throw new ExpType1();
}
else if(someOtherSituationTakesPlace()
{
throw new ExpType2();
}
public class Failure : Exception
{
IFailureHandling _handling;
public Failure(IFailureHandling handling)
{
//we're injecting how the failure should be handled
_handling = handling;
}
//If you need to provide additional info from
//the place where you catch, you can use parameter list of this method
public void Handle()
{
_handling.Perform();
}
}
if(sensorsFailed())
{
throw _failureFactory.CreateForCaseWhenSensorsAreDamaged();
}
try
{
PerformSomeLogic();
}
catch(Failure failure)
{
failure.Handle();
}
if(exp.GetType()==typeof(expType1))
{
if(exp.Message.Include("something went bad"))
{
if(exp.InnerException.Message == "Something inside went bad as well";
{
DoX();
DoY();
}
}
}
else if (exp.GetType()==typeof(expType2))
{
DoZ();
DoV();
}
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessage(message => message.Includes("something went bad"))
.WithInnerException<SomeInnerException>()
.HavingAMessage(innerMessage => innerMessage == "Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessageThatIncludes("something went bad")
.WithInnerException<SomeInnerException>()
.HavingAMessageEqualTo("Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
然后,我将创建一个工厂来创建这样的异常,并在此时使用处理程序绑定它们。例如:
public class FailureFactory
{
IFailureHandling _handlingOfCaseWhenSensorsAreDown,
IFailureHandling _handlingOfCaseWhenNetworkConnectionFailed
public FailureFactory(
IFailureHandling handlingOfCaseWhenSensorsAreDown,
IFailureHandling handlingOfCaseWhenNetworkConnectionFailed
//etc.
)
{
_handlingOfCaseWhenSensorsAreDown
= handlingOfCaseWhenSensorsAreDown;
_handlingOfCaseWhenNetworkConnectionFailed
= handlingOfCaseWhenNetworkConnectionFailed;
//etc.
}
public Failure CreateForCaseWhenSensorsAreDamaged()
{
return new Failure(_handlingOfCaseWhenSensorsAreDown);
}
public Failure CreateForCaseWhenNetworkConnectionFailed()
{
return new Failure(_handlingOfCaseWhenNetworkConnectionFailed);
}
}
通常情况下,每个系统只创建一个这样的工厂,并在实例化所有长期运行对象的位置执行此操作。通常,应用程序中有一个这样的位置,因此,在实例化工厂时,您应该能够通过构造函数传递希望它使用的所有对象,这将创建一个非常原始的fluent界面。记住,流畅的界面是关于可读性和流的,而不仅仅是放.a.dot.every.method.call:-:
var inCaseOfSensorDamagedLogItToDatabaseAndNotifyUser
= InCaseOfSensorDamagedLogItToDatabaseAndNotifyUser(
logger, translation, notificationChannel);
var inCaseOfNetworkDownCloseTheApplicationAndDumpMemory
= new InCaseOfNetworkDownCloseTheApplicationAndDumpMemory(
memoryDumpMechanism);
var failureFactory = new FailureFactory(
inCaseOfSensorDamagedLogItToDatabaseAndNotifyUser,
inCaseOfNetworkDownCloseTheApplicationAndDumpMemory
);
这样,抛出异常的位置和捕获异常的位置都与处理逻辑分离,这就是问题的不同之处!因此,我们概括了各种变化!当然,在此基础上,您可以免费提供更高级的流畅界面
现在,您抛出异常的每个地方都将如下所示:
if(someSituationTakesPlace())
{
throw new ExpType1();
}
else if(someOtherSituationTakesPlace()
{
throw new ExpType2();
}
public class Failure : Exception
{
IFailureHandling _handling;
public Failure(IFailureHandling handling)
{
//we're injecting how the failure should be handled
_handling = handling;
}
//If you need to provide additional info from
//the place where you catch, you can use parameter list of this method
public void Handle()
{
_handling.Perform();
}
}
if(sensorsFailed())
{
throw _failureFactory.CreateForCaseWhenSensorsAreDamaged();
}
try
{
PerformSomeLogic();
}
catch(Failure failure)
{
failure.Handle();
}
if(exp.GetType()==typeof(expType1))
{
if(exp.Message.Include("something went bad"))
{
if(exp.InnerException.Message == "Something inside went bad as well";
{
DoX();
DoY();
}
}
}
else if (exp.GetType()==typeof(expType2))
{
DoZ();
DoV();
}
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessage(message => message.Includes("something went bad"))
.WithInnerException<SomeInnerException>()
.HavingAMessage(innerMessage => innerMessage == "Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessageThatIncludes("something went bad")
.WithInnerException<SomeInnerException>()
.HavingAMessageEqualTo("Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
在一个地方,您可以捕捉到所有这些异常,如下所示:
if(someSituationTakesPlace())
{
throw new ExpType1();
}
else if(someOtherSituationTakesPlace()
{
throw new ExpType2();
}
public class Failure : Exception
{
IFailureHandling _handling;
public Failure(IFailureHandling handling)
{
//we're injecting how the failure should be handled
_handling = handling;
}
//If you need to provide additional info from
//the place where you catch, you can use parameter list of this method
public void Handle()
{
_handling.Perform();
}
}
if(sensorsFailed())
{
throw _failureFactory.CreateForCaseWhenSensorsAreDamaged();
}
try
{
PerformSomeLogic();
}
catch(Failure failure)
{
failure.Handle();
}
if(exp.GetType()==typeof(expType1))
{
if(exp.Message.Include("something went bad"))
{
if(exp.InnerException.Message == "Something inside went bad as well";
{
DoX();
DoY();
}
}
}
else if (exp.GetType()==typeof(expType2))
{
DoZ();
DoV();
}
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessage(message => message.Includes("something went bad"))
.WithInnerException<SomeInnerException>()
.HavingAMessage(innerMessage => innerMessage == "Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessageThatIncludes("something went bad")
.WithInnerException<SomeInnerException>()
.HavingAMessageEqualTo("Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
这样,您知道如何处理每个故障情况的唯一地方就是在创建FailureFactory类对象的逻辑中
第二个解决方案-使用处理程序
如果您不拥有引发异常的代码,或者在上面概述的解决方案中投入太高的成本或太高的风险,我会使用一个看起来类似FailureFactory的处理程序对象,但不是创建对象,而是自己执行处理:
public class FailureHandlingMechanism
{
_handlers = Dictionary<Type, IFailureHandling>();
public FailureHandler(Dictionary<Type, IFailureHandling> handlers)
{
_handlers = handlers;
}
public void Handle(Exception e)
{
//might add some checking whether key is in dictionary
_handlers[e.GetType()].Perform();
}
}
实例化这样的处理机制已经为您提供了一个非常原始的流畅界面:
var handlingMechanism = new HandlingMechanism(
new Dictionary<Type, IFailureHandling>()
{
{ typeof(NullPointerException), new LogErrorAndCloseApplication()}},
{ typeof(ArgumentException}, new LogErrorAndNotifyUser() }
};
如果希望以更流畅、噪音更小的方式配置这种处理机制,可以围绕处理机制创建一个生成器,该生成器具有向字典添加键和值的方法以及一个名为Build this的方法
为您创建了对象:
var handlingMechanismThatPerforms = new HandlingMechanismBuilder();
var logErrorAndCloseApplication = new LogErrorAndCloseApplication();
var logErrorAndNotifyUser = new LogErrorAndNotifyUser();
var handlingMechanism = handlingMechanismThatPerforms
.When<NullPointerException>(logErrorAndCloseApplication)
.When<ArgumentException>(logErrorAndNotifyUser)
.Build();
就这样。如果对你有任何帮助,请告诉我 披头士1692,请原谅,我将从重构异常处理开始,而不是直接跳到DSL部分 在你的问题中,你说: 我正在回顾代码库的一部分,接下来是异常处理部分,这部分非常混乱。我想换件更优雅的 我想这是你最关心的。因此,我将尝试为您提供一个如何使其更加优雅的指南-实际上,您提供的代码片段不优雅并不是关于它不是DSL或流畅的接口,而是关于设计质量。如果你的设计中有冗余和耦合,那么在冗余和耦合之上创建一个流畅的界面只会让它变得更糟糕 答案很长,我会参考一些代码质量,所以如果您需要进一步的解释,请告诉我。因为在做出这样的决定时涉及到很多变量,比如变更成本、代码所有权等。我将尝试为您提供最干净的解决方案,然后提供一个需要最少努力的解决方案 在这种情况下,最好应用经典设计模式的作者四人帮的建议。这条建议是:封装变化的内容。在您的情况下,故障处理是变化的,变化基于异常类型。我将如何在这里应用它 第一个解决方案-完全重构代码中的气味 我要问的第一个问题是:您是否可以修改引发异常的代码?如果是这样的话,我会尽量不在捕获异常的代码中进行封装,而是在抛出异常的代码中进行封装。这对您来说可能有些奇怪,但这可能会让您避免冗余。事实上,您的代码当前在两个地方耦合到一种类型的异常 第一个地方是抛出异常的位置,您必须知道要抛出哪个异常-非常简单,它可能如下所示:
if(someSituationTakesPlace())
{
throw new ExpType1();
}
else if(someOtherSituationTakesPlace()
{
throw new ExpType2();
}
public class Failure : Exception
{
IFailureHandling _handling;
public Failure(IFailureHandling handling)
{
//we're injecting how the failure should be handled
_handling = handling;
}
//If you need to provide additional info from
//the place where you catch, you can use parameter list of this method
public void Handle()
{
_handling.Perform();
}
}
if(sensorsFailed())
{
throw _failureFactory.CreateForCaseWhenSensorsAreDamaged();
}
try
{
PerformSomeLogic();
}
catch(Failure failure)
{
failure.Handle();
}
if(exp.GetType()==typeof(expType1))
{
if(exp.Message.Include("something went bad"))
{
if(exp.InnerException.Message == "Something inside went bad as well";
{
DoX();
DoY();
}
}
}
else if (exp.GetType()==typeof(expType2))
{
DoZ();
DoV();
}
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessage(message => message.Includes("something went bad"))
.WithInnerException<SomeInnerException>()
.HavingAMessage(innerMessage => innerMessage == "Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessageThatIncludes("something went bad")
.WithInnerException<SomeInnerException>()
.HavingAMessageEqualTo("Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
当然,条件可能更复杂,可能有多个不同的对象和方法可以抛出,但本质上,它总是归结为一系列的选择,比如在情况a中,抛出异常X
有这种映射的第二个地方是当您捕获异常时——您必须再次通过一系列if-else来找出它是什么情况,然后调用一些逻辑来处理它
为了避免这种冗余,我将决定抛出异常的处理方式——您应该在那里拥有所需的所有信息。因此,我首先定义一个异常类,如下所示:
if(someSituationTakesPlace())
{
throw new ExpType1();
}
else if(someOtherSituationTakesPlace()
{
throw new ExpType2();
}
public class Failure : Exception
{
IFailureHandling _handling;
public Failure(IFailureHandling handling)
{
//we're injecting how the failure should be handled
_handling = handling;
}
//If you need to provide additional info from
//the place where you catch, you can use parameter list of this method
public void Handle()
{
_handling.Perform();
}
}
if(sensorsFailed())
{
throw _failureFactory.CreateForCaseWhenSensorsAreDamaged();
}
try
{
PerformSomeLogic();
}
catch(Failure failure)
{
failure.Handle();
}
if(exp.GetType()==typeof(expType1))
{
if(exp.Message.Include("something went bad"))
{
if(exp.InnerException.Message == "Something inside went bad as well";
{
DoX();
DoY();
}
}
}
else if (exp.GetType()==typeof(expType2))
{
DoZ();
DoV();
}
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessage(message => message.Includes("something went bad"))
.WithInnerException<SomeInnerException>()
.HavingAMessage(innerMessage => innerMessage == "Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessageThatIncludes("something went bad")
.WithInnerException<SomeInnerException>()
.HavingAMessageEqualTo("Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
然后,我将创建一个工厂来创建这样的异常,并在此时使用处理程序绑定它们。例如:
public class FailureFactory
{
IFailureHandling _handlingOfCaseWhenSensorsAreDown,
IFailureHandling _handlingOfCaseWhenNetworkConnectionFailed
public FailureFactory(
IFailureHandling handlingOfCaseWhenSensorsAreDown,
IFailureHandling handlingOfCaseWhenNetworkConnectionFailed
//etc.
)
{
_handlingOfCaseWhenSensorsAreDown
= handlingOfCaseWhenSensorsAreDown;
_handlingOfCaseWhenNetworkConnectionFailed
= handlingOfCaseWhenNetworkConnectionFailed;
//etc.
}
public Failure CreateForCaseWhenSensorsAreDamaged()
{
return new Failure(_handlingOfCaseWhenSensorsAreDown);
}
public Failure CreateForCaseWhenNetworkConnectionFailed()
{
return new Failure(_handlingOfCaseWhenNetworkConnectionFailed);
}
}
通常情况下,每个系统只创建一个这样的工厂,并在实例化所有长期运行对象的位置执行此操作。通常,应用程序中有一个这样的位置,因此,在实例化工厂时,您应该能够通过构造函数传递希望它使用的所有对象,这将创建一个非常原始的fluent界面。记住,流畅的界面是关于可读性和流的,而不仅仅是放.a.dot.every.method.call:-:
var inCaseOfSensorDamagedLogItToDatabaseAndNotifyUser
= InCaseOfSensorDamagedLogItToDatabaseAndNotifyUser(
logger, translation, notificationChannel);
var inCaseOfNetworkDownCloseTheApplicationAndDumpMemory
= new InCaseOfNetworkDownCloseTheApplicationAndDumpMemory(
memoryDumpMechanism);
var failureFactory = new FailureFactory(
inCaseOfSensorDamagedLogItToDatabaseAndNotifyUser,
inCaseOfNetworkDownCloseTheApplicationAndDumpMemory
);
这样,抛出异常的位置和捕获异常的位置都与处理逻辑分离,这就是问题的不同之处!因此,我们概括了各种变化!当然,在此基础上,您可以免费提供更高级的流畅界面
现在,您抛出异常的每个地方都将如下所示:
if(someSituationTakesPlace())
{
throw new ExpType1();
}
else if(someOtherSituationTakesPlace()
{
throw new ExpType2();
}
public class Failure : Exception
{
IFailureHandling _handling;
public Failure(IFailureHandling handling)
{
//we're injecting how the failure should be handled
_handling = handling;
}
//If you need to provide additional info from
//the place where you catch, you can use parameter list of this method
public void Handle()
{
_handling.Perform();
}
}
if(sensorsFailed())
{
throw _failureFactory.CreateForCaseWhenSensorsAreDamaged();
}
try
{
PerformSomeLogic();
}
catch(Failure failure)
{
failure.Handle();
}
if(exp.GetType()==typeof(expType1))
{
if(exp.Message.Include("something went bad"))
{
if(exp.InnerException.Message == "Something inside went bad as well";
{
DoX();
DoY();
}
}
}
else if (exp.GetType()==typeof(expType2))
{
DoZ();
DoV();
}
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessage(message => message.Includes("something went bad"))
.WithInnerException<SomeInnerException>()
.HavingAMessage(innerMessage => innerMessage == "Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessageThatIncludes("something went bad")
.WithInnerException<SomeInnerException>()
.HavingAMessageEqualTo("Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
在一个地方,您可以捕捉到所有这些异常,如下所示:
if(someSituationTakesPlace())
{
throw new ExpType1();
}
else if(someOtherSituationTakesPlace()
{
throw new ExpType2();
}
public class Failure : Exception
{
IFailureHandling _handling;
public Failure(IFailureHandling handling)
{
//we're injecting how the failure should be handled
_handling = handling;
}
//If you need to provide additional info from
//the place where you catch, you can use parameter list of this method
public void Handle()
{
_handling.Perform();
}
}
if(sensorsFailed())
{
throw _failureFactory.CreateForCaseWhenSensorsAreDamaged();
}
try
{
PerformSomeLogic();
}
catch(Failure failure)
{
failure.Handle();
}
if(exp.GetType()==typeof(expType1))
{
if(exp.Message.Include("something went bad"))
{
if(exp.InnerException.Message == "Something inside went bad as well";
{
DoX();
DoY();
}
}
}
else if (exp.GetType()==typeof(expType2))
{
DoZ();
DoV();
}
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessage(message => message.Includes("something went bad"))
.WithInnerException<SomeInnerException>()
.HavingAMessage(innerMessage => innerMessage == "Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessageThatIncludes("something went bad")
.WithInnerException<SomeInnerException>()
.HavingAMessageEqualTo("Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
这样,您知道如何处理每个故障情况的唯一地方就是在创建FailureFactory类对象的逻辑中
第二个解决方案-使用处理程序
如果您不拥有引发异常的代码,或者在上面概述的解决方案中投入太高的成本或太高的风险,我会使用一个看起来类似FailureFactory的处理程序对象,但不是创建对象,而是自己执行处理:
public class FailureHandlingMechanism
{
_handlers = Dictionary<Type, IFailureHandling>();
public FailureHandler(Dictionary<Type, IFailureHandling> handlers)
{
_handlers = handlers;
}
public void Handle(Exception e)
{
//might add some checking whether key is in dictionary
_handlers[e.GetType()].Perform();
}
}
实例化这样的处理机制已经为您提供了一个非常原始的流畅界面:
var handlingMechanism = new HandlingMechanism(
new Dictionary<Type, IFailureHandling>()
{
{ typeof(NullPointerException), new LogErrorAndCloseApplication()}},
{ typeof(ArgumentException}, new LogErrorAndNotifyUser() }
};
如果希望以更流畅、噪音更小的方式配置此类处理机制,可以围绕处理机制创建一个生成器,该生成器具有向字典添加键和值的方法,以及一个名为Build的方法,该方法为您创建了对象:
var handlingMechanismThatPerforms = new HandlingMechanismBuilder();
var logErrorAndCloseApplication = new LogErrorAndCloseApplication();
var logErrorAndNotifyUser = new LogErrorAndNotifyUser();
var handlingMechanism = handlingMechanismThatPerforms
.When<NullPointerException>(logErrorAndCloseApplication)
.When<ArgumentException>(logErrorAndNotifyUser)
.Build();
就这样。如果对你有任何帮助,请告诉我 这是我第二次尝试回答你的问题。正如我正确理解的那样,您试图从这样的代码中摆脱嵌套的ifs和ELSE:
if(someSituationTakesPlace())
{
throw new ExpType1();
}
else if(someOtherSituationTakesPlace()
{
throw new ExpType2();
}
public class Failure : Exception
{
IFailureHandling _handling;
public Failure(IFailureHandling handling)
{
//we're injecting how the failure should be handled
_handling = handling;
}
//If you need to provide additional info from
//the place where you catch, you can use parameter list of this method
public void Handle()
{
_handling.Perform();
}
}
if(sensorsFailed())
{
throw _failureFactory.CreateForCaseWhenSensorsAreDamaged();
}
try
{
PerformSomeLogic();
}
catch(Failure failure)
{
failure.Handle();
}
if(exp.GetType()==typeof(expType1))
{
if(exp.Message.Include("something went bad"))
{
if(exp.InnerException.Message == "Something inside went bad as well";
{
DoX();
DoY();
}
}
}
else if (exp.GetType()==typeof(expType2))
{
DoZ();
DoV();
}
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessage(message => message.Includes("something went bad"))
.WithInnerException<SomeInnerException>()
.HavingAMessage(innerMessage => innerMessage == "Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessageThatIncludes("something went bad")
.WithInnerException<SomeInnerException>()
.HavingAMessageEqualTo("Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
现在考虑一下,您已经创建了一个链式API,其内容如下:
if(someSituationTakesPlace())
{
throw new ExpType1();
}
else if(someOtherSituationTakesPlace()
{
throw new ExpType2();
}
public class Failure : Exception
{
IFailureHandling _handling;
public Failure(IFailureHandling handling)
{
//we're injecting how the failure should be handled
_handling = handling;
}
//If you need to provide additional info from
//the place where you catch, you can use parameter list of this method
public void Handle()
{
_handling.Perform();
}
}
if(sensorsFailed())
{
throw _failureFactory.CreateForCaseWhenSensorsAreDamaged();
}
try
{
PerformSomeLogic();
}
catch(Failure failure)
{
failure.Handle();
}
if(exp.GetType()==typeof(expType1))
{
if(exp.Message.Include("something went bad"))
{
if(exp.InnerException.Message == "Something inside went bad as well";
{
DoX();
DoY();
}
}
}
else if (exp.GetType()==typeof(expType2))
{
DoZ();
DoV();
}
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessage(message => message.Includes("something went bad"))
.WithInnerException<SomeInnerException>()
.HavingAMessage(innerMessage => innerMessage == "Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessageThatIncludes("something went bad")
.WithInnerException<SomeInnerException>()
.HavingAMessageEqualTo("Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
让它:
if(situationA)
{
throw ExceptionXYZ();
}
else if (situationB)
{
throw ExceptionCVZF();
}
那么就不需要嵌套的if了
-您的异常处理将是:
try
{
XYZ()
}
catch(ExceptionXYZ)
{
DoX();
DoY();
}
catch(ExceptionCVZF)
{
DoZ();
DoV();
}
这是我第二次尝试回答你的问题。正如我正确理解的那样,您试图从这样的代码中摆脱嵌套的ifs和ELSE:
if(someSituationTakesPlace())
{
throw new ExpType1();
}
else if(someOtherSituationTakesPlace()
{
throw new ExpType2();
}
public class Failure : Exception
{
IFailureHandling _handling;
public Failure(IFailureHandling handling)
{
//we're injecting how the failure should be handled
_handling = handling;
}
//If you need to provide additional info from
//the place where you catch, you can use parameter list of this method
public void Handle()
{
_handling.Perform();
}
}
if(sensorsFailed())
{
throw _failureFactory.CreateForCaseWhenSensorsAreDamaged();
}
try
{
PerformSomeLogic();
}
catch(Failure failure)
{
failure.Handle();
}
if(exp.GetType()==typeof(expType1))
{
if(exp.Message.Include("something went bad"))
{
if(exp.InnerException.Message == "Something inside went bad as well";
{
DoX();
DoY();
}
}
}
else if (exp.GetType()==typeof(expType2))
{
DoZ();
DoV();
}
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessage(message => message.Includes("something went bad"))
.WithInnerException<SomeInnerException>()
.HavingAMessage(innerMessage => innerMessage == "Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessageThatIncludes("something went bad")
.WithInnerException<SomeInnerException>()
.HavingAMessageEqualTo("Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
现在考虑一下,您已经创建了一个链式API,其内容如下:
if(someSituationTakesPlace())
{
throw new ExpType1();
}
else if(someOtherSituationTakesPlace()
{
throw new ExpType2();
}
public class Failure : Exception
{
IFailureHandling _handling;
public Failure(IFailureHandling handling)
{
//we're injecting how the failure should be handled
_handling = handling;
}
//If you need to provide additional info from
//the place where you catch, you can use parameter list of this method
public void Handle()
{
_handling.Perform();
}
}
if(sensorsFailed())
{
throw _failureFactory.CreateForCaseWhenSensorsAreDamaged();
}
try
{
PerformSomeLogic();
}
catch(Failure failure)
{
failure.Handle();
}
if(exp.GetType()==typeof(expType1))
{
if(exp.Message.Include("something went bad"))
{
if(exp.InnerException.Message == "Something inside went bad as well";
{
DoX();
DoY();
}
}
}
else if (exp.GetType()==typeof(expType2))
{
DoZ();
DoV();
}
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessage(message => message.Includes("something went bad"))
.WithInnerException<SomeInnerException>()
.HavingAMessage(innerMessage => innerMessage == "Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
var handlingManager = new ExceptionHandlingManager();
handlingManager
.For<Exception>()
.HavingAMessageThatIncludes("something went bad")
.WithInnerException<SomeInnerException>()
.HavingAMessageEqualTo("Something inside went bad as well")
.Perform(() =>
{
DoX();
DoY();
});
让它:
if(situationA)
{
throw ExceptionXYZ();
}
else if (situationB)
{
throw ExceptionCVZF();
}
然后您将不需要嵌套的ifs-您的异常处理将是:
try
{
XYZ()
}
catch(ExceptionXYZ)
{
DoX();
DoY();
}
catch(ExceptionCVZF)
{
DoZ();
DoV();
}
我编写了一个简单的fluent异常处理程序。它易于扩展。您可以在这里查看它:也许它可以根据您的目标进行定制。我编写了一个简单的fluent异常处理程序。它易于扩展。您可以在这里查看:也许可以根据您的目标进行定制。fluent界面能为您带来什么?它将帮助我防止大量嵌套if,并且代码将易于维护。嗯,我想马丁并不是什么都对。@JohnSaunders:对于我们这些没有运行时宏功能的人来说,这是一种穷人的DSL形式,例如C程序员。fluent界面会给你买什么?它将帮助我防止大量嵌套if,代码也将很容易维护。嗯,我想马丁并不是什么都对。@JohnSaunders:对于我们这些没有运行时宏功能的人来说,这是一种可怜的DSL形式,比如C程序员。