干(不要重复自己)和如果分配 [英] DRY (Don't Repeat Yourself) and if assignements

查看:143
本文介绍了干(不要重复自己)和如果分配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为我忘记了一些明显的事情,但是我似乎无法找到一种方法来分配一个值,如果它确认一个条件尽可能保持DRY ...
一些代码来解释我的意思。 ..

  a =(b> 1)? b:c; 

甚至 a =(a> 1)? a:b;



所以当然这里没什么大不了的,但是如果要用方法调用替换它,(可能是一个产量)返回那里)或者其他什么,然后我必须把它叫两次......



我只看到将它存放在一个变量中,然后就像上面的代码一样...



有什么好主意吗?



编辑以便更好地理解:
假设我说'我我在xml文件中搜索一个值,使用空检查(?。?[])等等,这样就像

  string store_no = myXmlNode.SelectSingleNode(aChildNode)?. SelectSingleNode(myNode)?. Attributes?[store_no] ?. Value; 

所以在这里我将它存储在一个变量中,以便我可以稍后测试它的值。
如果我想检查一个特定的store_no!我必须做类似的事情

  store_no =(store_no ==STORE23)?store_no:unknown; 

...是的,不确定这个exa是否足够明确但这个想法就在这里;我可能不想将数据存储在变量(例如巨大的数据块)中是否有办法获得相同的结果?

解决方案

< blockquote>

我认为我忘记了一些明显的事情,但如果它确认一个条件尽可能保持DRY,我似乎找不到分配值的方法


让我们首先解除您的常见误解。



这完全是对DRY含义的误解。如果您有客户对象,你有一个地址对象和客户有字段 BillingCity BillingPostalCode HomeCity 等等,那么您的代码不是DRY,因为相同的信息在两个中冗余地表示地方。您应重新设计代码,以便 Customer 具有地址对象的集合。



现在,避免在整个节目中剪切和粘贴重复代码确实是一个好主意,但DRY是关于代码的设计。中等到大规模。 DRY绝对不意味着你的代码永远不应该在同一个表达式中使用相同的变量两次!



现在我们已经完成了这个,让我们来看看你对语言的批评。



我们经常处于表达式上下文的情况下 - 也就是说,一个很长的,可能是流利式的表达式,我们希望避免冗余工作。例如,我们可能有:

  x = M()> 0? M():0; 

也许拨打 M()两次是昂贵的,或者它可能不是幂等的。随你。无所谓。重点是,我们不想两次打电话。



令人恼火的是,我们必须退出表达式上下文并进入语句环境:

  var m = M(); 
x = m> 0? m:0;

这当然是合法的,但有点令人烦恼。此外,有些情况可能会有些棘手:

  N(P()??(M()> 0? M():0)); 

现在我们该怎么办?假设我们只想调用 M(),如果 P()为空。

  var t = default(T); 
var p = P();
if(p == null){
var m = M();
t = m> 0? m:0;
}其他{
t = p.Value;
}
N(t);

YUCK。 OMG太可怕了。



其他语言通过引入 let 表达式来解决这个问题。我们真正想要的是能够在表达式的中间引入一个新的局部。一个常见的语法是让EXPRESSION中的ID = EXPRESSION ID 成为一个具有特定含义的只读变量但是仅在范围内:

  N(P() ??(m = M?M()m> 0?m:0)); 

请注意,C# 支持表达式,但仅在查询理解中。如果它在语言中更普遍地支持它会很棒。



多年来有很多建议要添加 let 表达式,或者更通用的表格,顺序表达式,多年来进入C#。有关示例,请参阅github roslyn问题跟踪器。也许这会进入C#8;如果你想要它,请参加论坛。



那么你能做些什么呢?



事实证明是C#中的 let-expressions。 让z 中的x = y只是编写的好方法(((Func< X,Z>)(x => z)) (Y))。所以你可以写:

  N(P()??(((Func< int,int>)(m => ; m> 0?m:0))(M()))); 

但看起来几乎可怕。这是一个难以理解的混乱。



问题是lambda。这会更好:

  Func< int,int> f = m => m> 0? m:0; 
...
N(P()?? f(M()));

但这有点不透明。我们如何才能进一步改进?



我们可以使它成为一个局部函数,但更好的是,我们可以使它成为一个扩展方法并进行流畅的编程:

  public static int NotNegative(this int x)=> x> 0? x:0; 
...
N(P()?? M()。NotNegative());

完成。这只评估 M()一次,但超级奖金,它更容易阅读,因为现在程序文本代表正在执行的操作,而不是程序文本是一个难以阅读的标点符号。



小流畅的扩展方法可以使您的代码更容易阅读。养成使用它们的习惯。


I think I'm forgetting something evident but I can't seem to find a way to assign a value if it validates a condition remaining as DRY as possible... Some code to explain what I mean ...

a = (b > 1) ? b : c;

or even a = (a > 1) ? a : b;

So of course here it's no big deal but if a was to be replaced by an method call, (maybe a yield return there) or whatever, I would then have to call it twice...

Only thing I see is stocking it in a variable which would then be as the code above...

Any better idea?

Edit for better comprehension : Let's say I'm searching a value in a xml file, with null checks (?. ?[]) etc so something like

string store_no = myXmlNode.SelectSingleNode("aChildNode")?.SelectSingleNode("myNode")?.Attributes?["store_no]?.Value;

So here I store this in a variable so that I can test its value later. If I want to check a specific store_no !I would have to do something like

store_no = (store_no=="STORE23")? store_no : "unknown";

...Yeah not sure if it is quite explicit enough with this example but the idea is here; I may not want to store data in a variable (huge data block for example) is there a way to get the same result?

解决方案

I think I'm forgetting something evident but I can't seem to find a way to assign a value if it validates a condition remaining as DRY as possible

Let's start by disabusing you of a common misapprehension.

This is a complete misrepresentation of what DRY means. If you have a Customer object and you have an Address object and Customer has fields BillingCity and BillingPostalCode and HomeCity and so on, then your code is not DRY because the same information was represented redundantly in two places. You should redesign your code so that a Customer has a collection of Address objects.

Now, it is indeed a good idea to avoid cut-and-pasting duplicate code all over the show, but DRY is about the design of code in the medium to large scale. DRY absolutely does not mean that your code should never use the same variable twice in the same expression!

Now that we've got that out of the way, let's look at your critique of the language.

We are often in situations where we are in an "expression context" -- that is, a long, possibly fluent-style expression, where we want to avoid doing redundant work. For example, we might have:

x = M() > 0 ? M() : 0;

Maybe calling M() twice is expensive, or maybe it is not idempotent. Whatever. Doesn't matter. Point is, we don't want to call it twice.

It is irritating that we have to drop out of expression context and into statement context:

var m = M();
x = m > 0 ? m : 0;

That is of course legal, but it is a bit vexing. Also, there are some contexts where it's possibly tricky:

N(P() ?? (M() > 0 ? M() : 0));

Now what do we do? There's no obvious way to preserve the semantics without writing it out in longhand, assuming that we only want to call M() if P() is null.

var t = default(T);
var p = P();
if (p == null) {
  var m = M();
  t = m > 0 ? m : 0;
} else  {
  t = p.Value;
}
N(t);

YUCK. OMG THAT IS SO HORRIBLE.

Other languages solve this problem by introducing let expressions. What we would really like is to be able to introduce a new local in the middle of an expression. A common syntax is let ID = EXPRESSION in EXPRESSION and ID becomes a read-only variable that has a particular meaning but is only in scope in the in:

N(P() ?? (let m = M() in m > 0 ? m : 0));

Note that C# does support let expressions but only in a query comprehension. It would be great if it supported it more generally in the language.

There have been many proposals over the years to add let expressions, or their more general form, sequencing expressions, into C# over the years. See the github roslyn issue tracker for examples. Maybe this will get into C# 8; if you want it, go participate in the forums.

So what can you do in the meanwhile?

It turns out there are let-expressions in C#. let x = y in z is simply a nice way to write (((Func<X, Z>)(x=>z))(y)). So you could write:

N(P() ?? (((Func<int, int>)(m => m > 0 ? m : 0))(M())));

but that looks almost as horrid. That's an unreadable mess.

The problem is the lambda. This would be better:

Func<int, int> f = m => m > 0 ? m : 0;
...
N(P() ?? f(M()));

But that's a little bit opaque. How can we improve on this further?

We could make it a local function, but even better, we could make it an extension method and do fluent programming:

public static int NotNegative(this int x) => x > 0 ? x : 0;
...
N( P() ?? M().NotNegative());

Done. This only evaluates M() once, but super bonus, it is easier to read because now the program text represents the operation being performed on it, rather than the program text being a slew of hard-to-read punctuation.

Little fluent-style extension methods can make your code a lot easier to read. Get in the habit of using them.

这篇关于干(不要重复自己)和如果分配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆