33

次の C# コードは判読できますか?

private bool CanExecuteAdd(string parameter) {
    return
        this.Script == null ? false
        : parameter == "Step" ? true
        : parameter == "Element" ? this.ElementSelectedInLibrary != null && this.SelectedStep != null
        : parameter == "Choice" ? this.SelectedElement != null
        : parameter == "Jump" ? this.SelectedStep != null
        : parameter == "Conditional jump" ? false
        : false.Throw("Unknown Add parameter {0} in XAML.".F(parameter));
}

ここで、Throw は次のように定義されます。

public static T Throw<T>(this T ignored, string message) {
    throw new Exception(message);
}

私はそれが慣用的な C# ではないことを知っています。しかし、あなたはそれを一目で、あるいは二度目で理解できますか?それとも、私はあまりにも遠くに迷いましたか?

4

15 に答える 15

31

スイッチを使ってみませんか?ずっと読みやすいと思います。

private bool CanExecuteAdd(string parameter) {
    if (Script == null)
        return false;

    switch (parameter) {
        case "Step":
            return true;
        case "Element":
            return ElementSelectedInLibrary != null && SelectedStep != null;
        case "Choice":
            return SelectedElement != null;
        case "Jump":
            return SelectedStep != null;
        case "Conditional jump":
            return false;
        default:
            throw new Exception(string.Format("Unknown Add parameter {0} in XAML.", parameter));
    }
}
于 2010-02-23T17:57:13.783 に答える
28

私はJavaでこの種のコードをかなりの量使用しました。私は少し好きではありませんが、false.Throwこのような複数の条件 (特にこのようにフォーマットされたもの) を持つことは私の見解では問題ありません。

初めて見たときは少し奇妙ですが、その後は知っておくと便利なパターンです。

ここで使用する別の方法の 1 つfalse.Throwは、次のようなものです。

bool? ret = this.Script == null ? false
    : parameter == "Step" ? true
    : parameter == "Element" ? this.ElementSelectedInLibrary != null && this.SelectedStep != null
    : parameter == "Choice" ? this.SelectedElement != null
    : parameter == "Jump" ? this.SelectedStep != null
    : parameter == "Conditional jump" ? false
    : null;

if (ret == null)
{
    throw new ArgumentException(
       string.Format("Unknown Add parameter {0} in XAML.", parameter);
}
return ret.Value;

編集: 実際、この場合、if/elseこのパターンも使用しません... switch/case を使用します。必要に応じて、これは非常にコンパクトになります。

if (this.Script == null)
{
    return false;
}
switch (parameter)
{
    case "Step": return true;
    case "Element": return this.ElementSelectedInLibrary != null && this.SelectedStep != null;
    case "Choice": return this.SelectedElement != null;
    case "Jump": return this.SelectedStep != null;
    default: throw new ArgumentException(
        string.Format("Unknown Add parameter {0} in XAML.", parameter);
}
于 2010-02-23T17:43:05.677 に答える
11

私の経験則: 副作用のないものには式を使用してください。副作用が 1 つあるものと制御フローにはステートメントを使用します。

スローは事実上副作用です。値を計算するのではなく、制御フローを変更します。あなたは価値を計算し、計算し、計算し、計算し、そしてブーム、副作用を計算しています。そのようなコードは混乱を招き、厄介なものだと思います。私は、制御フローは、計算のように見えるものの副作用ではなく、ステートメント内にあるべきだと言います。

于 2010-02-23T21:10:07.647 に答える
8

私は判読不能に投票します。

構文は正しいのですが、やや複雑です。あえて言うなら「伝統的」ではないため、多くの開発者は、読んでいるものを確実に理解するために時間を無駄にする必要があります。理想的な状況ではありません。

読みやすさは間違いなく優れたコーディングの重要な要素の 1 つであり、ほとんどの開発者にとってサンプルはすぐには読めないと思います。

于 2010-02-23T17:47:35.270 に答える
6

私は条件演算子が好きで、それをよく使います。

この例は、レイアウトと使用法から演算子の性質が明確でないため、少し混乱します。

少なくとも、このフォーマットを使用して、選択肢と選択肢を明確にしたいと思います。

choice
  ? true-case
  : false-case

しかし、それをコードに適用すると、このように構成を使用する際の明確さの欠如が明らかになります。

return
    this.Script == null 
                ? false 
                : parameter == "Step" 
                    ? true
                    : parameter == "Element" 
                        ? this.ElementSelectedInLibrary != null && this.SelectedStep != null
                        : parameter == "Choice" 
                            ? this.SelectedElement != null
                            : parameter == "Jump" 
                                ? this.SelectedStep != null
                                : parameter == "Conditional jump" 
                                        ? false
                                        : false.Throw("Unknown Add parameter {0} in XAML.".F(parameter));

これは、switchステートメントのように条件演算子を使用しようとしているように感じます。ここでは、switchステートメント、さらにはコマンドパターンのようなデザインパターンの方がはるかに明確です。

于 2010-02-23T17:56:53.333 に答える
5

私は本当にこのコードが好きではありません。理解するのに15秒以上かかったので諦めました。

if/then が望ましいでしょう。

于 2010-02-23T17:46:31.217 に答える
3

ネストされた三項をスイッチに変換します。特に明らかな利点がない場合は、1つの制御構造に、組み込み構造が完全に実行することを不十分または判読不能に実行するように強制しないでください。

于 2010-02-23T17:54:10.437 に答える
2

null許容型のboolを使用してみませんか?

private bool? CanExecuteAdd(string parameter) {
return
    this.Script == null ? false
    : parameter == "Step" ? true
    : parameter == "Element" ? this.ElementSelectedInLibrary != null && this.SelectedStep != null
    : parameter == "Choice" ? this.SelectedElement != null
    : parameter == "Jump" ? this.SelectedStep != null
    : parameter == "Conditional jump" ? false
    : null;

}

于 2010-02-23T17:48:08.663 に答える
2

最初は怖かったのですが、実際にはC#でこれほど明確に書く方法を考えることはできません。結果に一連のFuncsをマッピングする方法を考えようとしていましたが、さらに醜くなりました。

実際の条件を解析するのは大雑把ですが、少なくとも意図を理解するのは簡単です。ただし、スイッチブロックを使用し、その他すべてを特殊なケースとして処理することをお勧めします。

于 2010-02-23T17:49:24.553 に答える
2

非慣用的であるということは、読者が読んでいる内容が、それが意味していると考えていることを意味するかどうかについて、時間をかけて考えさせることを意味します。

したがって、読みやすいことは、洗練された(つまり、疑わしい)リーダーをあまり購入しません. これは、賢いために賢いというケースのように私には思えます。

ここでスイッチまたはelse if構造を使用しない理由はありますか?

于 2010-02-23T17:44:28.383 に答える
1

CおよびC++では、説明されている使用法は慣用的であり、演算子の理由です。三項条件と連鎖if-then-elseの利点は、既知の型の式であるということです。C ++では、実際に書くことができます

foo_t foo = bar_p ? bar
          : qux_p ? qux
          : woz_p ? woz
          : (throw SomeExpression(), foo_t())
          ;

スローのために作成されないfoo_tを返すコンマ演算子に注意してください。

于 2011-05-07T16:34:45.640 に答える
1

残念ながら、三項演算子(?:)は、C言語では一般的なイディオムではありません。C、C ++、C#の開発者の多くは、慣れていないか、慣れていないために読むのをやめなければなりません。これを使って。それはそれを悪い言語機能または判読不能にするわけではありませんが、それらの同じ開発者は、彼らが不快な言語機能をネストしているため、OPの例を判読不能と呼ぶかもしれません。

判読できない例は見つかりません。ネストされた三項演算子を何度も見ました。ただし、文字列に対して「パラメータ」をチェックするには、スイッチを使用する方が望ましいと思います。

私にとってはるかに魅力的なのは、「this」パラメーターを無視するThrow拡張メソッドです。42.Throw(...)はどういう意味ですか?私がコードをレビューしているなら、私はそれを悪いデザインと呼ぶでしょう。

于 2010-02-23T19:26:55.063 に答える
1

読むのが難しすぎます。最初に例外を処理してください。

それぞれのケースを独自の if で処理すると、より複雑な条件を設定できます。

これは数少ないケースの 1 つであり、メソッドでこれほど多くの個別の戻り値が許容される場合があります

private bool CanExecuteAdd(string parameter) 
{       
    if (this.Script == null)
        return false;

    if (parameter.NotIn([] {"Step", "Element", "Choice", "Jump", "Conditional jump"})
        throw new Exception("Unknown Add parameter {0} in XAML.".F(parameter));

    if (parameter == "Step") 
        return true;

    if (parameter == "Element")
        this.ElementSelectedInLibrary != null && this.SelectedStep != null;

        // etc, etc
}

ああ、そして .NotIn は拡張メソッドであり、これとは逆であると私は想像します (これが必要なものとまったく正確であるとは言えません)

public static bool In<T>(this T obj, IEnumerable<T> arr)
{
    return arr.Contains(obj);
}
于 2010-02-23T18:26:33.840 に答える
1

私には問題ないように見えますが、Throw メソッドを次のように変更します。

static TObject Throw<TObject, TException>(this TObject ignored, TException exception)
{
   throw exception;
}

これにより、スローされる例外の種類を指定できます。

于 2010-02-23T19:03:37.863 に答える
0

実は三項演算子がここまで押し出されたのを見たことがありません。しかし、私はあなたがどこに向かっているのか理解していました。また、Jon に同意します。false.Throw の部分は好きではありません。

于 2010-02-23T17:46:50.053 に答える