如果.Create()无法实例化,它应该返回空对象,null还是抛出异常?

时间:2009-06-10 13:21:51

标签: c# exception-handling instantiation

我希望能够使用这种代码实例化我的应用程序中的任何对象:

SmartForm smartForm = SmartForm.Create("id = 23");
Customer customer = Customer.Create("id = 222");

我现在正在讨论如果该对象不存在,Create()应该返回什么。

  • 如果Create()返回空对象,那么这是一种“空模式”,我仍然可以在我的应用程序周围传递该对象并在其上调用方法,这使得使用此模型进行编程既方便又简单

  • 如果Create()返回 null ,那么我需要在每次实例化后检查对象是否等于null,这使得编程更乏味但更明确。这样做的一个问题是,如果你忘记检查null,你的应用程序可能会工作很长时间而你不知道你没有检查null,然后突然中断

  • 如果Create()抛出异常,它基本上与返回null相同,但是通过让你为每个实例创建一个try,next,finally块,使编程变得更加乏味,但你可以抛出各种类型的异常(你不能使用null解决方案),这可能会冒出来,这样你就可以更明确地处理UI上的深层错误,所以我认为这是最强大的解决方案,尽管会产生尝试/捕捉代码膨胀

所以它似乎是轻盈/稳健性权衡有没有人有任何根据这些决定做出决定的经验,因为这个决定你遇到了优点或缺点?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestFactory234.Models
{
    public class SmartForm : Item
    {
        public string IdCode { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public int LabelWidth { get; set; }

        public SmartForm() { }

        private SmartForm(string loadCode)
        {
            _loadCode = loadCode;
            TryToInstantiateFromDatabase();
        }

        public static SmartForm Create(string loadCode)
        {
            SmartForm smartForm = new SmartForm(loadCode);

            if (!smartForm.IsEmpty())
            {
                return smartForm;
            }
            else
            {
                return null;
            }
        }
    }
}

6 个答案:

答案 0 :(得分:6)

这取决于 - 如果它失败是因为某些东西肯定是错误的,那么异常会使编程更容易 - 你不会在每次调用时写一个try / catch,你只是让异常冒出来。将其与检查null /空白返回值进行比较,然后然后抛出异常。

这听起来像是使用ArgumentException,IMO的正确时间。

如果您发现自己创建了try / catch“膨胀”,请查看为什么您真的需要捕获异常,而不是让它们冒泡。

答案 1 :(得分:2)

如果它返回一个空白对象,那么你将继续假设它是有效的 - 或者必须进行某种精心测试以确定它是否为空白。如果它返回null,你将始终必须检查null(也许这很好)。我希望它抛出异常 - 假设您的代码是为了不应该发生而设计的。如果这是正常情况,那么null可能是更好的选择。

答案 2 :(得分:2)

当默认行为是创建实例时,异常行为将失败并创建 - >例外

你会用EmptyObject做什么?你说你仍然可以传递它 - 这真的有意义吗?当你打电话给他们时,这些方法会做什么?

也许你应该实现第二个 TryCreate()方法。

我实现了Exception-variant,但这取决于你需要的行为。

答案 3 :(得分:1)

您的示例代码调用“从DB尝试加载”方法,并且Create约定看起来很像Castle ActiveRecord对象。为什么不分离Get / Create数据库操作,允许框架完成工作并依赖它们的约定?

[ActiveRecord("Forms")]
public class SmartForm : Item
{
    [PrimaryKey("Id")]
    public string IdCode { get; set; }
    [Property]
    public string Title { get; set; }
    [Property]
    public string Description { get; set; }
    [Property]
    public int LabelWidth { get; set; }
}

你得到/创建这样的实例

SmartForm entity = ActiveRecordMediator<SmartForm>.Find(1);
SmartForm otherEntity = ActiveRecordMediator<SmartForm>.FindFirst(/* criteria */);

还有很多其他方法可用于查找实例。我想你会发现ActiveRecord的defaults regarding throwing exceptions,返回null,或者在集合的情况下,是一个空集合,非常一致且实现得很好。

答案 4 :(得分:0)

如果要创建表单工厂,最好传递枚举而不是字符串(当然,除非代表插件架构)。

答案 5 :(得分:0)

如果可以预见创建可能会失败,但很多应用程序代码会期望它能够正常工作,那么你真的应该实现两个版本的创建方法,其中一个应该成功或抛出异常,并且其他的应该通过除抛出异常之外的某些方式指示预期的失败,并且仅针对调用者可能没有预料到的失败抛出异常(例如CpuIsOnFireException)。执行此操作的常见模式是让TryCreate方法返回指示成功的布尔值,将创建的参数存储到by-ref参数。我真的不喜欢这种模式,因为除了传递失败状态之外,它没有提供任何指示任何东西的方法(即没有关于它失败的原因)。我认为让“try”函数返回new或null返回可能会更好,但是有一个by-ref参数指示失败的原因。请注意,此方法可以更好地使用隐式类型(例如C#中的“var”关键字)。