C# 方法链接的最佳实践(“返回此”)

C# 方法链接的最佳实践(“返回此”),c#,.net,return-value,C#,.net,Return Value,我有一个名为DatabaseRow的抽象类,它在派生和构造之后,主要是从Load(objectid)方法加载的 我有很多代码可以创建类的新实例,从ID加载它,然后返回类。我想将这段代码简化为一行代码(为了简洁起见,有很多类只包含返回这些加载实例的属性列表) 我有两种方法可以考虑这样做,但在我看来这两种方法都不“正确” 1.我可以返回这个在我的Load方法的末尾,使用returnnew-Derived().Load(id) 2。我可以创建一个泛型方法来返回加载的方法 public static T

我有一个名为
DatabaseRow
的抽象类,它在派生和构造之后,主要是从
Load(objectid)
方法加载的

我有很多代码可以创建类的新实例,从ID加载它,然后返回类。我想将这段代码简化为一行代码(为了简洁起见,有很多类只包含返回这些加载实例的属性列表)

我有两种方法可以考虑这样做,但在我看来这两种方法都不“正确”

1.我可以
返回这个在我的
Load
方法的末尾,使用
returnnew-Derived().Load(id)

2。我可以创建一个泛型方法来返回加载的方法

public static T LoadRow<T>(object id) where T : DatabaseRow, new()
{
    T row = new T();
    row.Load(id);
    return row;
}

第一名在一些圈子里越来越受欢迎;当有一个定义了大量这些方法的接口并且可以组装长链时,通常称为fluent编程。成功实现这一点的关键是永远不要定义一个有时返回
this
,但有时返回
null
的方法。如果
总是返回此
(除非有例外),这是非常好的样式


就我个人而言,我并不喜欢第二种解决方案,因为它可以说违反了“一个责任”原则。

虽然我个人喜欢返回此
的方法,因为它允许链接它们,但我认为在.NET框架中(直到Linq),这是不受欢迎的。我突然想到的原因是:

方法返回结果或更改对象的状态。返回<代码>这
有点双重含义:改变对象的状态,然后返回一个“结果”-除了结果是修改后的原始对象。这不符合用户的期望

那么:

public class Derived : DatabaseRow
{
    public Derived(object id):
    {
        Load(id);
    }
}
然后像这样使用它:

return new Derived(id);

我个人认为,链接对对象实例有实际副作用的方法调用是一种不好的做法。老实说,我认为这两个例子都是相当丑陋的“黑客”,其唯一目的是节省两行代码。我不认为结果实际上更具可读性


如果您希望立即加载一条记录,我可能更愿意提供一个构造函数变量,它接受您从中加载的ID,并使对象在构造时自动填充自己,尽管当我想到它时,老实说,我一点也不想费心——在一行中塞满更多的信息并不会产生更多可读性和可维护性的代码。

只有在不加载行的情况下,选项1才是可以接受的。这是由于模式允许您执行以下操作:

return new Derived();
就个人而言,我更喜欢静态方法。但我怀疑这只是个人喜好的问题

正如ssg所说的,另一个选项(让我们称之为选项3)是在派生中重载构造函数,这也会起作用,但是拥有大量构造函数往往会令人困惑,因为调用代码中没有任何描述正在发生的事情的内容

备选案文1:

return new Derived().Load(10);
备选案文2:

return Derived.Load(10);
备选案文3:

return new Derived(10);

选项1看起来像是创建了一个多余的对象。选项2是好的,因为它做它看起来像做的事情。选项3让人对它的作用感到困惑。

我非常同意你在这里的第二段。实际上,我最初使用的是与您的解决方案类似的方法,但我决定不使用它,而是改为Load方法,因为我认为构造函数不应该有那么多功能(在本例中,执行SQL查询)@Connell Watkins:我以前也曾对构造函数进行过类似的思考,但现在,人们倾向于将它们视为对象处于可用状态的保证。因此,如果对象仅在调用Load方法后才使用,那么您真的可以将其放入构造函数中!在我的例子中,我有一个类继承了
DatabaseRow
,有5个属性,它们都使用相同的函数。拥有5行代码,类似于
public-Derived-MyProperty{get{return new-Derived().Load(myInt);}}
比将属性分成多行代码要整洁得多。但是属性代码的“整洁”到底有什么关系呢?在大多数情况下,属性代码无论如何都应该由VisualStudio折叠,而且您也不必总是查看类实现。这就是说,在属性访问上构造和加载数据一开始似乎相当危险。如果有人不知道结果需要缓存,这可能会很快导致性能不佳和/或意外行为。仅此而已!!!我现在觉得自己像个白痴。您关于缓存的评论提醒我,我已经在DatabaseRow类的底部创建了这个函数
protected T GetLinkedRow(字符串键),其中T:DatabaseRow,new()
加载该行并根据
key
的值将其缓存到字典中。由于我同意您所说的一切,您的第一段和注释触发了我的解决方案,我觉得这应该是可以接受的答案。谢谢。有一个类而不加载它是很有可能的。如果要在数据库中创建新行,则需要创建一个新实例,填充属性,然后调用
Save()
方法。你是说通用的静态方法吗?或者每个派生类中都有一个静态方法?啊,我刚刚看到了你的编辑。选项2看起来很完美,但问题是它需要我为这种类型的每个派生类创建相同的静态方法,这似乎是不必要的。
return new Derived(10);