强制执行所需功能的电话
-
09-06-2019 - |
题
我有一个"地位"类,使用这样的:
Status MyFunction()
{
if(...) // something bad
return new Status(false, "Something went wrong")
else
return new Status(true, "OK");
}
你的想法。所有呼叫者的MyFunction 应该 检查返回的状况:
Status myStatus = MyFunction();
if ( ! myStatus.IsOK() )
// handle it, show a message,...
懒惰的呼叫者不过可以忽略的状态。
MyFunction(); // call function and ignore returned Status
或
{
Status myStatus = MyFunction();
} // lose all references to myStatus, without calling IsOK() on it
是否有可能使这不可能?例如一扔异常
在一般:是否有可能编写C#类上你 已 叫某些功能?
在C++版的状况类,我可以写测试上一些私人bool bIsChecked在 析构 和一些环钟声时没有人检查的实例。
什么是同等的选择C#?我读的地方,"你不想要一个析构在C#类"
是的处置方法的IDisposable界面的一个选择吗?
在这种情况下,没有不受管理的资源。此外,它还是不确定 时 GC会处理的对象。当它最终得到设置,它仍然有可能知道,当你忽略这一特定的状态的实例?"使用"的关键词并帮助,但再一次,它不是 需要 懒惰的来电。
解决方案
我相当肯定你不能得到你想要的效果,作为回报价值从一个方法。C#就不能做一些事情C++可以。然而,有些丑陋的方式得到类似的效果如下:
using System;
public class Example
{
public class Toy
{
private bool inCupboard = false;
public void Play() { Console.WriteLine("Playing."); }
public void PutAway() { inCupboard = true; }
public bool IsInCupboard { get { return inCupboard; } }
}
public delegate void ToyUseCallback(Toy toy);
public class Parent
{
public static void RequestToy(ToyUseCallback callback)
{
Toy toy = new Toy();
callback(toy);
if (!toy.IsInCupboard)
{
throw new Exception("You didn't put your toy in the cupboard!");
}
}
}
public class Child
{
public static void Play()
{
Parent.RequestToy(delegate(Toy toy)
{
toy.Play();
// Oops! Forgot to put the toy away!
});
}
}
public static void Main()
{
Child.Play();
Console.ReadLine();
}
}
在非常简单的例子,你得到的一个实例玩具通过呼吁父母。RequestToy, 并通过它的委托.而不是返回玩具、方法立即呼吁委托有玩具,它必须呼叫上架在返回之前,或RequestToy方法将引发一个例外。我没有权利要求的智慧使用这种技术--实际上在所有"错误"的例子的一个例外是几乎可以肯定一个更好的选择--但我认为这涉及关于接近,你可以得到你的原始请求。
其他提示
我知道这并不直接回答你的问题,但如果"错误"在功能(意想不到的情况下)我觉得你应该被投掷的一个例外而不是使用状态返回代码。
然后把它留给叫捕获和处理这一例外如果可以的话,或许它propogate如果叫的是无法处理的情况。
异常引发可能的一个自定义的类型(如果这是适当的。
对于 预期 替代结果,我同意@Jon Limjap的建议。我喜欢一个bool返回的类型和前缀的方法名称与"尝试",la:
bool TryMyFunction(out Status status)
{
}
如果你真的想要要求用户检索的结果MyFunction,你可能会想要取消它,而不是与使用一个或ref变量,例如,
void MyFunction(out Status status)
{
}
它可能看起来很丑但至少它能确保一个可变的是通过进入功能,将选取结果你需要它拿起。
@伊恩
该问题与例外情况是,如果它发生的事情有点太多的时候,你可能会花费太多的系统资源的例外。一个例外应该真正地被用于 特殊 错误、不完全的预计的消息。
甚至系统。网。引发问福汇,他们说一个例外时返回HTTP status code是一个错误代码。典型的方式来处理它,是结束一试/抓住周围。你仍然可以忽略的状态中的代码抓块。
你可以,但是,有一个参数的行动< 状态>这样的呼叫者是被迫通过一个回呼功能接受的状态,然后检查,看看如果他们叫它。
void MyFunction(Action<Status> callback)
{ bool errorHappened = false;
if (somethingBadHappend) errorHappened = true;
Status status = (errorHappend)
? new Status(false, "Something went wrong")
: new Status(true, "OK");
callback(status)
if (!status.isOkWasCalled)
throw new Exception("Please call IsOK() on Status").
}
MyFunction(status => if (!status.IsOK()) onerror());
如果你在担心他们的呼唤IsOK()没有做任何事情,使用的表达< Func< 状态,bool>>,而不是然后你就可以分析lambda看到他们做什么用的状况:
void MyFunction(Expression<Func<Status,bool>> callback)
{ if (!visitCallbackExpressionTreeAndCheckForIsOKHandlingPattern(callback))
throw new Exception
("Please handle any error statuses in your callback");
bool errorHappened = false;
if (somethingBadHappend) errorHappened = true;
Status status = (errorHappend)
? new Status(false, "Something went wrong")
: new Status(true, "OK");
callback.Compile()(status);
}
MyFunction(status => status.IsOK() ? true : onerror());
或放弃的状态类共和使他们通过在一个委派的成功,另一个用于一个错误:
void MyFunction(Action success, Action error)
{ if (somethingBadHappened) error(); else success();
}
MyFunction(()=>;,()=>handleError());
使用状态作一回值记得我的"老天"的C节目,当你返回的一个整数如下0如果事情没有工作。
那岂不是更好,如果你把一个异常的时候(如你把它放) 事了?如果一些"懒惰的代码"没赶上你除外,你知道。
而不是迫使某人检查的状态,我认为你应该认为程序是意识到这一风险不这样做,并有理由采取的行动。你不知道如何的功能是将在未来使用而放置一个限制等,只有限制的可能性。
这将肯定是不错的编译器检查,而不是通过表达。:/ 看不到任何方式做到,虽然...
你可以扔掉一个例外:
throw MyException;
[global::System.Serializable]
public class MyException : Exception
{
//
// For guidelines regarding the creation of new exception types, see
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp
// and
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp
//
public MyException () { }
public MyException ( string message ) : base( message ) { }
public MyException ( string message, Exception inner ) : base( message, inner ) { }
protected MyException (
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context )
: base( info, context ) { }
}
上述例外是完全可以定制以您的要求。
有一件事我会说是这样的,我会让它的呼叫者检查返回代码,这是他们的责任你只是提供手段和接口。此外,这是一个很大的更有效使用返回代码和检查的状况与如果一个声明,而不是trhowing例外情况。如果它真的是一个 特殊 情况,然后通过的所有装置扔掉...但是说如果你没有打开一个装置,那么它可能会更加审慎坚持的返回代码。
@保罗你可以做到这一点,在编制时间 可扩展C#.
海湾合作委员会有一个 warn_unused_result
属性,它适用于这样的事情。也许微软编译器有类似的东西。
一个模式,这有时可能是有益的,如果对象它代码问题的请求,将只能使用通过一个单一的线(*),是有目的保持的一个错误的国家,并说,如果操作失败的对象,将无法使用,直到错误的状态是reset(未来的请求应立即失败,最好通过投掷立即例外,其中包括关于以前的失败和新的要求)。在情况下调用代码发生的预见一个问题,这可以允许的呼叫代码处理该问题的更清洁的比,如果一个例外被扔;问题不是被忽略的呼叫代码通常会结束触发的一个例外,不久之后他们会发生。
(*)如果资源将通过多线程,创建一个包装对象对于每个线程,并让每个线程的请求通过其自己的包装。
这种模式是可用的,即使在情况下的例外情况是不是,有时可以非常实际的,在这样的情况。在一般情况下,然而,一些变化的尝试做模式通常更好。有方法扔异常失败,除非叫明确指示(通过使用 TryXX
法),失败的预期。如果呼叫者说失败的预期,但不处理他们,这是他们的问题。一个可以结合起来的尝试做一个第二层的保护使用方案上面,但是我不确定它是否将是值得的成本。