C# 同时从方法返回对象引用和异常

C# 同时从方法返回对象引用和异常,c#,singleton,C#,Singleton,我只是尝试在WinForms中实现Singleton模式,以便在应用程序生命周期中只保留一个表单实例,但我面临一个困难 如果singleton实例存在,我想抛出异常,并同时返回相同的实例引用 SingletonForm.cs 您要么抛出异常,要么返回实例。对于单例,不应抛出异常,只要返回实例(如果存在) 单例模式不应该阻止您甚至警告您多次调用GetInstance。它应该只返回第一次创建的相同实例 我只是想也许有一天我需要同时使用这两种方法 这就是我问的原因 抛出异常会立即从函数返回,因为这意味

我只是尝试在WinForms中实现Singleton模式,以便在应用程序生命周期中只保留一个表单实例,但我面临一个困难

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

SingletonForm.cs
您要么抛出异常,要么返回实例。对于单例,不应抛出异常,只要返回实例(如果存在)

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

我只是想也许有一天我需要同时使用这两种方法 这就是我问的原因

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

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

您要么抛出异常,要么返回实例。对于单例,不应抛出异常,只要返回实例(如果存在)

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

我只是想也许有一天我需要同时使用这两种方法 这就是我问的原因

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

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

从设计的角度来看,不,你没有。异常应表示系统需要从中恢复的严重、意外错误。你说的是将其用作错误代码。如果你要这样做,不要抛出异常——通过在你的单例上设置一个标志或者返回一个null或者其他什么来指示问题


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

从设计角度看,不,您没有。异常应表示系统需要从中恢复的严重、意外错误。你说的是将其用作错误代码。如果你要这样做,不要抛出异常——通过在你的单例上设置一个标志或者返回一个null或者其他什么来指示问题


但是,在您的特定情况下,只需去掉异常逻辑即可。singleton设计模式旨在成为全局变量的存储库,因此预期公共静态实例实际上会被调用不止一次,许多singleton用户倾向于在其代码库中的几乎每个类中使用它。

我的工作假设是,您需要知道它是否是一个新实例,并且它将在返回后更改您的执行路径。一种方法是,尽管我不寒而栗地使用异常选项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.TryGetValueKEY,out VALUE中看到的内容。

我的假设是,您实际需要知道它是否是新实例,并且它将在返回后更改您的执行路径。一种方法是,尽管我不寒而栗地使用异常选项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.TryGetValueKEY,out VALUE中看到的内容。

在这种情况下,为什么要抛出异常?这对我来说毫无意义。请注意,您的单例实现不是线程安全的。这个问题很难得到答案,因为这似乎是一个非常糟糕的做法,但您可以使用out参数。public static SingletonForm GetInstanceout Exception ex{}@BrokenGlass:我只是觉得可能有一天我可能需要同时使用这两种方法,这就是为什么我问,我只是在玩这个singleton示例……在这种情况下,为什么要抛出一个异常?这对我来说毫无意义。请注意,您的单例实现不是线程安全的。这个问题很难得到答案,因为这似乎是一个非常糟糕的做法,但您可以使用out参数。公共静态单例表单GetInstanceou
t Exception ex{}@BrokenGlass:我只是想可能有一天我可能需要同时使用这两种方法这就是为什么我问,我只是在玩这个单例样本…通过在你的单例上设置一个标志来说明问题详细阐述这一点很有意思,而不是抛出异常,您可以保留一个静态实例计数器变量,在每次有人调用GetInstance时递增该变量。在名为TooManyAccesses或其他内容的单例上公开一个静态布尔属性,如果实例计数器不止一个,则将其设置为true。通过在你的单例上设置一个标志来指出问题。阐述这一点很有意思,你可以保留一个静态实例计数器变量,在每次有人调用GetInstance时递增,而不是抛出异常。在名为TooManyAccesses或其他内容的单例上公开一个静态布尔属性,如果实例计数器不止一个,则将其设置为true。类似的东西。我添加了一些关于同时使用两者的一般建议。谢谢。。请检查我的问题2。您应该为您的问题2提出一个新的StackOverflow问题,这样更多的人会看到它并能够回答。我认为单例可以继承用于测试目的,但否则通常不会从单例继承。好的,在上发布的新问题,我添加了一些关于同时使用两者的一般建议。谢谢。。请检查我的问题2。您应该为您的问题2提出一个新的StackOverflow问题,这样更多的人会看到它并能够回答。我认为出于测试目的,单例是可以继承的,但否则你通常不会从单例继承