我有一个来自第三方程序集的类(所以我无法编辑它):
public class MyClass
{
private bool _loggedIn;
public void Login() {_loggedIn = true;}
public void Logout() {
if (!_loggedIn) throw new InvalidOperationException();
_loggedIn = false;
}
}
现在,假设我有一个MyClass
的实例(我不知道_loggedIn
),我需要调用LogOut
。以下哪种避免致命异常的方法通常会更快? (任何其他方法也可以):
LogOut
,如果_loggedIn == false
,请抓住异常_loggedIn == true
,如果是,则仅调用LogOut
答案 0 :(得分:4)
这取决于您希望在应用程序中看到的不变量。
1。如果您希望有很多MyClass
具有不同的状态(登录,注销),那么最好避免异常开销(因为异常是< strong>异常情况)并使用一些特定的公共IsLoggedIn
属性(显然是为了避免反射)或某些TryXxxxx
类似的方法。
即使您无法修改原始代码,也没有人阻止您将其包裹起来:
public class MyWrappedClass
{
public Boolean IsLoggedIn {get; private set;}
private MyClass m_Log;
public MyWrappedClass ()
{
this.m_Log = new MyClass();
this.IsLoggedIn = false;
}
public void Log()
{
try
{
this.m_Log.LogIn();
this.IsLoggedIn = true;
}
catch
{
this.IsLoggedIn = false;
}
}
public void LogOut()
{
try
{
this.m_Log.LogOut();
this.IsLoggedIn = false;
}
catch
{
this.IsLoggedIn = true;
}
}
}
您甚至可以进一步实施IDisposable接口以避免手动LogIn-LogOut管理:
public class MyWrappedClass
{
private class LogSessionToken : IDisposable
{
private MyWrappedClass parent;
public LogSessionToken (MyWrappedClass parent)
{
parent.LogIn();
}
public void Dispose()
{
parent.LogOut();
}
}
public IDisposable LogSession()
{
return new LogSessionToken (this);
}
// ...
}
并像
一样使用它using (var logToken = wrappedInstance.LogSession)
{
// do the work.
} // No need to worry about manual LogOut
2。如果您希望以适当的方式只使用少量MyClass
,那么根本不处理异常会更好 - 如果发生了错误,那么它是一些编程错误,因此程序将被终止。
答案 1 :(得分:2)
首先,如果你的类没有公开LoggedIn
的至少一个只读属性,那么听起来有一个相当大的设计缺陷。
对于速度,使用反射通常会更快,特别是如果您使用FieldInfo
缓存Func<bool>
或构建System.Linq.Expressions
。这是因为Exceptions在抛出时会收集大量调试信息,包括StackTrace
,这可能很昂贵。
与任何事情一样,通常最好对这些操作进行测试,因为有时优化或其他因素可能会让您感到惊讶。
答案 2 :(得分:0)
如果模式if (CanFoo) Foo();
非常出现,那么这往往意味着非常强烈:
正确编写的客户端会知道何时能够或不能调用Foo
。客户不知道的事实表明它可能在其他方面存在缺陷。
公开CanFoo
和Foo
的类还应该公开一个方法Foo
如果可能且适当(如果无法确定预期的后置条件,该方法应该抛出,但如果在通话之前建立了后置条件,则应该默默返回
如果第一类不能控制应该提供这样的方法但是没有,那么最干净的方法可能是编写自己的包装方法,其语义反映了缺失方法本应具有的方法。如果该类的更高版本实现了缺少的方法,那么更改一个代码以使用该实现可能比重构大量if (CanFoo)
构造更容易。
LogOut
方法抛出异常将是一件好事,但是在客户端代码只想确保它被注销的情况下,可以无条件调用的EnsureLoggedOut
方法比为此目的添加额外的客户端代码更清晰。