【问题标题】:Returning object reference and Exception from method same time同时从方法返回对象引用和异常
【发布时间】:2012-02-01 15:52:37
【问题描述】:

我只是尝试在 WinForms 中实现单例模式,这样只有一个表单实例留在应用程序生命中,但我遇到了困难

如果单例的实例存在,我想抛出异常并同时返回相同的实例引用。

SingletonForm.cs

public class SingletonForm : BaseFormcs
{
    private static SingletonForm _instance;
    //To stop new keyword from instantiation 
    private SingletonForm()
    { }
    public static SingletonForm GetInstance()
    {
        if (_instance == null)
            return _instance = new SingletonForm();

        else
        {
            throw new Exception("Form already exists"); // execution returns from here
            return _instance; // Warning : Unreachable code detected
            //I also want to return instance reference.
        }

    }
}

【问题讨论】:

  • 在这种情况下为什么要抛出异常?这对我来说没有多大意义。
  • 请注意,您的单例实现不是线程安全的。
  • 这个问题几乎不值得回答,因为这似乎是一种非常糟糕的做法,但您可以使用 out 参数。公共静态 SingletonForm GetInstance(out Exception ex) { }
  • @BrokenGlass:我只是想有时我可能需要同时使用两者,这就是我问的原因,我只是在玩这个单例样本......

标签: c# singleton


【解决方案1】:

您要么抛出异常,要么返回一个实例。在单例的情况下,不应抛出异常,如果存在则返回实例。

单例模式不应阻止您(甚至警告您)多次调用 GetInstance。它应该只返回第一次创建的同一个实例。

我只是想有时我可能需要同时使用两者 这就是我问的原因

抛出异常会立即从函数中返回,因为这意味着发生了意外错误。在另一种情况下,您可能希望抛出异常,但前提是某些条件为真(例如,参数验证失败)。否则,您返回一个值。这是一个例子:

public int SomeFunction(String someArgument)
{
    if (someArgument == null) throw new ArgumentNullException("someArgument");
    int retVal = 0;
    //Some code here
    return retVal;
}

【讨论】:

  • 我添加了一些关于“同时使用两者”的一般建议。
  • 谢谢你。请检查我的问题 2
  • 你应该为你的问题 2 提出一个新的 StackOverflow 问题,这样更多的人会看到它并能够回答。我认为 Singleton 可以被继承用于测试目的,但否则你通常不会从 Singleton 继承。
  • 好的,新问题发布在stackoverflow.com/questions/9100523/…
【解决方案2】:

从设计的角度来看,不,你没有。异常应该表示您的系统需要从中恢复的严重的、未预料到的错误。您正在谈论将其用作错误代码。如果您要这样做,请不要抛出异常——通过在您的单例上设置标志或返回 null 或其他内容来指示问题。

但是,在您的具体情况下,只需摆脱异常逻辑即可。单例设计模式旨在成为全局变量的存储库,因此预计公共静态实例将被多次调用(事实上,许多单例用户倾向于在其代码库中的几乎每个类中使用它)。

【讨论】:

  • "通过在你的单例上设置一个标志来表明一个问题"请详细说明这一点
  • 意思是,你可以保留一个静态实例计数器变量,而不是抛出异常,每次有人调用 GetInstance() 时递增。在 Singleton 上公开一个名为 TooManyAccesses 的静态布尔属性,如果实例计数器大于一个,则将其设置为 true。类似的东西。
【解决方案3】:

我正在假设您有一个案例,您实际上需要知道它是否是一个新实例,并且它会在返回后更改您的执行路径。一种方法是使用异常(选项 1)(尽管我不寒而栗)。但您更有可能希望使用选项 2 来简单地在返回值上进行分支。

public class SingletonForm : BaseFormcs
{
    private static SingletonForm _instance;
    //To stop new keyword from instantiation 
    private SingletonForm()
    { }
    // ------- Option #1
    // Use an OUT parameter for the instance, so it's set before the exception
    public static void GetInstance(out SingletonForm form)
    {
        if (_instance == null)
        {
            _instance = new SingletonForm();
            form = _instance;
            return;
        }
        form = _instance;
        throw new Exception("Form already exists"); // execution returns from here
        // return isn't needed, since you threw an exception.
        // You really, really shouldn't do this. Consider instead...
    }

    // -------- Option #2
    // Same as above, but the return value tells you whether it's shiny and new
    public static bool GetInstance(out SingletonForm form)
    {
        if (_instance == null)
        {
            _instance = new SingletonForm();
            form = _instance;
            return true; // yes, you created a new one
        }
        form = _instance;
        return false; // no, you used an extant one
    }
}

第二个选项可能是您最好的选择,因为它更符合您在 Dictionary.TryGetValue(KEY key, out VALUE value) 中看到的内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-06
    • 2021-01-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多