我有一个"地位"类,使用这样的:

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 法),失败的预期。如果呼叫者说失败的预期,但不处理他们,这是他们的问题。一个可以结合起来的尝试做一个第二层的保护使用方案上面,但是我不确定它是否将是值得的成本。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top