更流利的C#/ .NET
我的一位同事想出了这个,我想知道别人怎么想? 就个人而言,我发现它很有趣,但想知道它是否太大了? 代码示例如下。 底部的扩展方法。
请一般的想法。 可以添加的其他扩展方法?
var ddl = Page.FindControl("LocationDropDownList") as DropDownList; ddl.Visible = true; ddl.SelectedValue = "123"; if(isAdmin) ddl .SelectedValue = "111";
变为:
Page.FindControl("LocationDropDownList") .CastAs() .With(d => d.Visible = true) .With(d => d.SelectedValue = "123") .WithIf(isAdmin, d => d.Items.Add(new ListItem("Admin", "1")));
要么:
Page.FindControl("LocationDropDownList") .CastAs() .With(d => { d.Visible = true; d.SelectedValue = "123"; }) .WithIf(isAdmin, d => d.SelectedValue = "111");
扩展方法:
public static TResult CastAs(this object obj) where TResult : class { return obj as TResult; } public static T With(this T t, Action action) { if (action == null) throw new ArgumentNullException("action"); action(t); return t; } public static T WithIf(this T t, bool condition, Action action) { if (action == null) throw new ArgumentNullException("action"); if (condition) action(t); return t; }
我编写清晰代码的经验法则是: 将所有副作用放在语句中; 非语句表达式应该没有副作用。
您的第一个程序版本明确遵循此规则。 第二个版本显然违反了它。
另外一个想法:如果我要读取你所显示的代码之类的代码,我自然会认为代码的目的是构建一个代表那些操作的延迟评估结构 – 这正是查询理解的原因所在。 C#3就是以这种方式构建的。 查询表达式的结果是表示查询的延迟应用程序的对象。
如果您的目的是捕捉“在我选择的后期以延迟方式执行这些副作用”的概念,那么这是一种明智的方法。 基本上你正在建立的是一个副作用的monad。 如果您的意图仅仅是为急切执行的代码提供不同的语法,那么这只是令人困惑,冗长和不必要的。
除了让读者感到困惑之外,我认为没有任何好处。 关于我的回答者,我想知道哪个星球更具可读性。 据我所知,第一个版本具有或多或少的完美可读性,而这是相当可读的,但让读者想知道在With
和WithIf
是否发生了一些奇怪的魔法。
与第一个版本相比,它更长,更难打字,更不明显,性能更低。
我想我没看到新版本能给你带来什么。 原件非常清晰,不那么罗嗦。 我猜它会更快。 除非有明显的好处,否则我会避免使用(滥用?)这样的语言function。
再投票“没用”。 除了With
方法包装序列语句之外, With
extension方法不会执行任何操作。 C#已经有一个用于测序语句的内置函数,它被调用;
。
类似地, WithIf
包装if语句而不对控制流进行任何修改。 从我的角度来看,你只是邀请自己采用以下方法:
public static T For( this T t, int start, Func cond, Action f) { for(int i = start; cond(i); i++) { f(t, i); } return t; }
原件更具可读性。
最简单的API更改是使FindControl()返回的对象成为一个Builder-esque的东西(其中所有set方法都返回’this’):
Page.FindControl("LocationDropDownList") .setVisible(true) .setSelectedValue(isAdmin ? "111" : "123");
这是一个有趣的扩展使用,我很欣赏它的优点。 我不确定我是否会使用它,但如果您的团队喜欢它,那么请务必使用它。
如果我看过它,这是一些滥用扩展方法!
它们只是不同的编码风格,你的意思是“太大的离开”? 离开什么? 从你习惯的? 只有你可以决定。 我会说VB的With
块对代码可读性的弊大于利,我不会尝试在C#中复制行为,但这只是我的偏好。
我几乎总是将它用于FindControl
(是的,强烈输入到RepeaterItem
,它不一定是,但这是我用过的唯一的东西):
public static T FindControl(this RepeaterItem item, string id) { return item.FindControl(id) as T; }
并调用它:
Literal myLiteral = e.Item.FindControl("myLiteral");
我对第一个版本感觉更舒服。 阅读和理解的时间更短。 我同意如果您熟悉并且熟悉With方法,扩展方法也可以,但在这种情况下它的好处是什么?
小调。 从个人经验来看,我会改变:
if(isAdmin) ddl.SelectedValue = "111";
至
if(isAdmin) { ddl.SelectedValue = "111"; }
要么
if(isAdmin) { ddl.SelectedValue = "111"; }
这样可以节省您的调试时间。
如果这是一种语言function:
With(Page.FindControl("LocationDropDownList") as DropDownList) { Visible = true; SelectedValue = "123"; if(isAdmin) Add(new ListItem( "111")); }
你会赢得一些东西:
- 避免变异对象的冗余
- “With”块中提供的所有语言function
以上尝试模仿风格而不会获得好处。 货物崇拜 。
(注意:我确实理解反对它的各种论点,但它仍然很好)
顺便说一句,我的一些C ++ Win32 UI Helpers包含使用类似于您想要实现的链接的setter:
LVItem(m_lc,idx)。SetText(_T(“Hello”))。SetImg(12).SetLParam(id);
在那种情况下,我最少赢得“无冗余”,但这是因为我没有属性。
我预测整个“流畅的界面”时尚将是2000年代的“匈牙利符号”。 我个人认为它看起来不是很干净,如果你有多个开发人员都有自己的偏好,那么它就有可能变得非常不一致。
看起来你的同事是一个Lambda Junkie。
我认为可读性问题是主观的,我个人对你所做的事情没有任何问题。 如果您的组织“批准”它,我会考虑使用它。
我认为这个概念是合理的,如果你将“With”改为“Let”,它将更具“function性”或“F#-ish”。 个人意见。
Page.FindControl("LocationDropDownList") .CastAs() .Let(d => d.Visible = true) .Let(d => d.SelectedValue = "123");
我的2美分:它看起来很好,我唯一的评论是,“有”意味着当你实际设置房产时,“在哪里”或“有”。 我建议使用类似“执行”,“执行”或“设置”的方法名称,但也许这只是我奇怪的世界观。
怎么样:
Page.WithControl("LocationDropDownList") .Do(d => d.Visible = true) .Do(d => d.SelectedValue = "123") .DoIf(isAdmin, d => d.Items.Add(new ListItem("Admin", "1")));
我会坚持使用第一个版本。 您发布的内容太聪明,无法立即对阅读代码的人有用。
你甚至可以更进一步,取消“var”:
DropDownList ddl = (DropDownList) Page.FindControl("ddlName");
这是一个关于如何制作比它需要的更复杂的完美学习案例。
第一个版本是明确的,除了正常的语言结构之外不需要额外的知识。
我说坚持第一个版本没有扩展方法或lamba表达式。 这些是相对较新的概念,因此没有多少开发人员可以处理它们,但在数据库中使用数据检索/操作之外。 如果您使用它们,您可能会受到维护成本的影响。 很高兴地说“如果这对你来说是希腊语的话”; 但在现实生活中,这可能是最好的方法。
关于“流畅的界面”C#已经为初始化程序提供了很好的语法,这对于(恕我直言)更好,尝试使用流畅的风格。 当然,在您的示例中,您没有初始化新对象,而是更改现有对象。 我对Fluent界面的全部专业知识来自维基百科的30秒扫描,但我认为JeeBee的答案更多的是Fluent编程的精神,尽管我可能稍微改变一下:
Page.FindDropDownList("LocationDropDownList") .setVisible(true) .setAdminSelectedValue("111") .setSelectedValue("123")
有人可能会说这更具可读性,特别是对于没有属性的语言,但我仍然认为它在C#中没有意义。
在某些情况下,精心构造的流畅接口可能非常有用。 首先,因为开发人员被提供有限数量的选项,他们(通常)易于正确使用并且难以正确使用。 其次,由于句子类似于结构,它们可以是一种很好的清晰方式来表达你的意图,特别是在构建复杂对象时。
我发现流畅的接口在开发测试代码时非常有用,在这些代码中经常需要构建大量具有轻微变化的域对象。 我还成功地使用它们作为引入装饰器模式和消除过多方法重载的方法。
如果有人有兴趣了解更多关于流畅的界面,我建议您查看Martin Fowler 正在进行的这项工作 。
好的经验法则:
如果您对代码的第一印象是“这很聪明” – 这可能不是一个好主意 。
好的代码应该简单,可读,并且只有在绝对必要时才“聪明” 。