2

コマンドライン引数を解析するプログラムまたはアルゴリズムを作成しました。まず、有効な引数とその属性 (フラグ、セパレーターなど) を指定する必要があります。

今、私は返すヘルパー関数を持っています: :ペアが見つからなかった場合Tuple<Tuple<Argument, String>, String>、タプル (これもタプルです) の最初の要素には「キーと値のペア」が含まれます。null2 番目の要素には、オプションとして識別された文字列が含まれており、セパレータは" "(値がコマンド ラインの次の要素になることを意味します)

その関数のコードは次のとおりです。

private Tuple<Tuple<Argument, String>, Argument> f(string e, List<Argument> valid) {
    var p = valid.Find( x => { return e.StartsWith( x.value ); } );
    if ( p == null )
        return new Tuple<Tuple<Argument, String>, Argument>( null, null );
    if ( p.flag )
        return new Tuple<Tuple<Argument, String>, Argument>( new Tuple<Argument, String>( p, "" ), null );
    if ( p.separator.Equals(" ") && p.value.Length == e.Length )
        return new Tuple<Tuple<Argument, String>, Argument>( null, p );
    var si = e.IndexOf(p.separator);
    if ( si != p.value.Length )
        return new Tuple<Tuple<Argument, String>, Argument>( null, null );
    return new Tuple<Tuple<Argument, String>, Argument>( new Tuple<Argument, String>( p, e.Substring( si + p.separator.Length ) ), null );
}

これを短く書く方法はありますか?そこにジェネリックを明示的に配置する必要がありますか?

明らかに、そのための独自のクラスを作成することが解決策になります。でも他にないの?

参考までに、Scala の同じコードは次のようになります。

val po = valid.find(p => e.startsWith(p.value))
po match {
    case Some(p) =>
        if ( p.flag )
            (Some((p, "")), None)
        else if ( p.separator.matches(" |\t") && p.value.length == e.length )
            (None, Some(p))
        else {
            val si = e.indexOf(p.separator)
            if ( si != p.value.length )
                (None, None)
            else
                (Some((p, e.substring(si + p.separator.length))), None)
        }
    case _ => (None, None)
}

さらに、コンパクトな方法で開始する方法はありますListsか? Tuplesのように、List(1, 2, 3, 4)または(Key, Value)代わりにTuple<KeyType, ValueType>(Key, Value)

よろしく、
ダニエル。

4

3 に答える 3

8

typedefを使用してコードをクリーンアップできます。技術的には、C#にはtypedefがありませんが、usingを使用してそれらをシミュレートできます。このようなもの:

using MyTuple = Tuple<Tuple<Argument, string>, Argument>;
using MyTuple2 = Tuple<Argument, string>;

public class MyClass {

    private MyTuple f(string e, List<Argument> valid) {
        var p = valid.Find( x => { return e.StartsWith( x.value ); } );
        if ( p == null )
           return new MyTuple( null, null );
        if ( p.flag )
           return new MyTuple( new MyTuple2( p, "" ), null );
        if ( p.separator.Equals(" ") && p.value.Length == e.Length )
            return new MyTuple( null, p );
        var si = e.IndexOf(p.separator);
        if ( si != p.value.Length )
            return MyTuple( null, null );
        return new MyTuple( new MyTuple2( p, 
            e.Substring( si + p.separator.Length ) ), null );
    }
}

初期化についての質問については、よくわかりません。タプルには、コンストラクター引数を使用したコンパクトな初期化メソッドがすでにあります。

リストでは、次のような初期化子を使用できます。

var s = new List<string> { "one", "two", "three" };
于 2013-02-04T23:35:28.947 に答える
4

タプルタイプを明示的に宣言することの「醜さ」を示す行を見てみましょう。

// ugly code
return new Tuple<Tuple<Argument, String>, Argument>( new Tuple<Argument, String>( p, "" ), null );

1)慣用的なC#はおそらく明示的にクラスを定義します

class ArgumentMatch {
    public Argument Key;
    public string Value;
    public Argument Unmatched;
}
// if you define the constructor
return new ArgumentMatch(p, "", null);
// or using object initializer syntax,
return new ArgumentMatch { Key = p, Value = "" };

2)明示的なタプル宣言を回避するために、独自の一般的なユーティリティ関数を作成できます。C#は、コンストラクターではなく、関数の型を推測します。

// using standard static method
static Tuple<T,U> MakeTuple<T,U>(T a, U b) { return new Tuple<T,U>(a,b); }
// and extension method (I don't personally like this since it's a bit 
// of a name-space pollutant)
static Tuple<T,U> Pair<T,U>(this T a, U b) { return new Tuple<T,U>(a,b); }

return MakeTuple(MakeTuple(p, ""), (Argument)null); 
return p.Pair("").Pair((Argument)null);

3)F#は、scalaの例をほぼ1行ずつ翻訳したものです。Scalaの使用に問題がない場合は、.NETでF#を使用することを検討してください。

// F# example code
match valid.find(fun x -> e.StartsWith(x.Value)) with
| Some(p) ->
    if p.flag then
        (p, ""),None
    elif p.separator = " " && p.Value.Length = e.Length then
        (None,None),Some(p)
 ....
于 2013-02-04T23:56:56.987 に答える