4

StringまたはStringBuilder引数で使用される汎用メソッドを作成します。引数の 2 番目の単語の位置を返します (単語はスペースと改行で区切ることができます)。引数の使用については[]Length()以下の醜いコードよりも優れたものを発明できませんでした。それを行うよりエレガントな方法はありますか?

int PositionOfTheSecondWord<T>(T text) // T can be String or StringBuilder
{
    int pos = 0;
    int state = 0;
    char c;

    // Get length of the text
    // UGLY!
    int length = text is StringBuilder ? (text as StringBuilder).Length : (text as String).Length;

    while (pos <= length - 1)
    {
        // Get the next character
        // UGLY!
        c = text is StringBuilder ? (text as StringBuilder)[pos] : (text as String)[pos];

        if (c == ' ' || c == '\n') // space
        {
            if (state == 1)
                state = 2; // 2 means the space between the first and the second word has begun
        }
        else // a letter
            if (state == 0)
                state = 1; // 1 means the first word has begun
            if (state == 2)
                return pos;

        pos++;

    }

    return -1;

}

PS StringBuilder が巨大になる可能性があるため、String 引数の関数を作成して StringBuilder.ToString() から呼び出すことはできません。

4

4 に答える 4

4

オーバーロードされたメソッドを使用するのが最善の方法だと思います。例えば:

int PostionOfTheSecondWord(string text)
{
    // Code optimized for strings.
}

int PostionOfTheSecondWord(StringBuilder text)
{
    // Code optimized for StringBuilder.
}

これにより、コードが読みやすくなり、維持しやすくなり、パフォーマンスが大幅に向上します。

これがあなたの探求に役立つことを願っています。

于 2012-09-16T07:27:12.113 に答える
1

メソッドの長さによっては、これがポリモーフィズムの状況になる可能性があります。

他の回答で述べたように、string互いにStringBuilder関連していません。したがって、それらに対して同じメソッドを使用する唯一の機会は、関連するこれら 2 つのタイプのラッパーを作成することです。

次のように、メソッドでラッパー基本クラスを定義できます。

public abstract class ScannableStringBase
{
    public abstract int Length { get; }

    public abstract char this[int index] { get; }

    public int PositionOfTheSecondWord()
    {
        int pos = 0;
        int state = 0;
        char c;

        int length = this.Length;

        while (pos <= length - 1)
        {
            c = this[pos];

            if (c == ' ' || c == '\n') // space
            {
                if (state == 1)
                    state = 2; // 2 means the space between the first and the second word has begun
            }
            else // a letter
                if (state == 0)
                    state = 1; // 1 means the first word has begun
                if (state == 2)
                    return pos;

            pos++;
        }

        return -1;

    }
}

そのクラスから、必要な値の型を処理するサブクラスを派生させます。

public class ScannableString : ScannableStringBase
{
    public ScannableString(string value)
    {
        this.stringValue = value;
    }

    private readonly string stringValue;

    public override int Length {
        get {
            return stringValue.Length;
        }
    }

    public override char this[int index] {
        get {
            return stringValue[index];
        }
    }
}

public class ScannableStringBuilder : ScannableStringBase
{
    public ScannableString(stringBuilder value)
    {
        this.stringBuilder = value;
    }

    private readonly string stringBuilder;

    public override int Length {
        get {
            return stringBuilder.Length;
        }
    }

    public override char this[int index] {
        get {
            return stringBuilder[index];
        }
    }
}

要約すると、次のようになります。

  • PositionOfTheSecondWord()基本クラスで一度だけ定義されるため、コードの重複はありません。
  • メソッドはorPositionOfTheSecondWord()以外では呼び出すことができないため、型安全性。stringStringBuilder
  • 拡張性。3 番目のタイプをサポートしたい場合は、単純に からさらに別のクラスを派生させることができるためですScannableStringBase

考えられる欠点の 1 つは、事前にどこかで分析する型を区別する必要があるため、インスタンス化するか、インスタンス化するかを決定できることScannableStringですScannableStringBuilder

于 2012-09-16T08:12:53.837 に答える
0
int GetPos(string text)
    {
        int length = text.Length;
        for (int i = 0; i < length; i++)
        {
            if (GetChar(text, i) == ' ')
            {
                return i;
            }
        }

        return -1;
    }

    int GetPos(StringBuilder sb)
    {
        int length = sb.Length;
        for (int i = 0; i < length; i++)
        {
            if (GetChar(sb, i) == ' ')
            {
                return i;
            }
        }

        return -1;
    }

    char GetChar<T>(T text, int pos)
    {
        if (text.GetType() == typeof(StringBuilder))
        {
            return (text as StringBuilder)[pos];
        }
        else if (text.GetType() == typeof(String))
        {
            return (text as String)[pos];
        }
        else
        {
            throw new ArgumentException("Wrong parameter, T must be string or StringBuilder");
        }
    }
于 2012-09-16T07:38:52.930 に答える
0

ジェネリック メソッドを使用する場合は、この最も単純なコードを使用して同じ効果を得ることができます。

// T can be String or StringBuilder:
static int PositionOfTheSecondWordNew<T>(T text) 
{
    int pos = -1;
    string[] word;

    // If T is string or StringBuilder this line is not necessary:
    if ((text is StringBuilder) || (text is string)) 
    {
        word = text.ToString().Split(new char[]{' ', '\n'});
        pos = word[0].Length;
    }
    return pos;
}
于 2012-09-16T07:54:50.157 に答える