2

このような色構造で機能するコードがいくつかあります

public void ChangeColor()
{
    thisColor.R = thisColor.R + 5;
}

ここで、渡されたものに応じて異なる変数を変更するメソッドを作成する必要があります。コードは次のようになります。

public void ChangeColor(int RGBValue)
{
    switch(RGBValue)
    {
        case 1:
            thisColor.R = thisColor.R + 5;
            break;
        case 2:
            thiscolor.B = thisColor.B + 5;
            break;
    }
}

さて、これは私が通常は決して疑問に思わないことです。#region ステートメントをその周りに投げて、1 日と呼びますが、これは私が持っているものの単なる例であり、実際の関数はかなり長いです。

私はそれを次のようにしたい:

public void ChangeColor(int RGBValue)
{
    thiscolor.RGBValue = thiscolor.RGBValue;
}

したがって、基本的に、値は使用されている変数を参照します。これに名前はありますか?これがReflectionの目的ですか?またはそのようなもの.これを行う方法はありますか?

4

7 に答える 7

5

これがあなたの望むものかどうかは 100% わかりません。しかし、与えられた例では、これがあなたが求めているもののように思えます。

ref次のキーワードを使用できる場合があります。

public void ChangeColor(ref int color)
{
    color += 5;
}

void SomeMethod()
{
    ChangeColor(ref thisColor.R); //Change the red value
    ChangeColor(ref thisColor.B); //Change the blue value
}
于 2010-03-27T00:51:53.690 に答える
2

これは間違いなく反射の目的ではありません。実際、ここには多くの問題があるようです。ここで確認してみましょう - 次のメソッドを変更します。

public void ChangeColor(int RGBValue)
{
    switch(...)
    {
        case ...
        case ...
        case ...
    }
}

このようなものに:

public void ChangeColor(int RGBValue)
{
    thisColor.{something-from-RGBValue} += 5;
}

これに関する問題は次のとおりです。

  • メソッドの名前 は、メソッドが実際に何をするかを正確にChangeColor表していません。おそらくこれは匿名化の成果物ですが、それでもこのメソッドの名前はひどいものです。

  • パラメーター は、引数の内容または動作を正確に説明RGBValueしていません。名前とタイプから、実際の RGB カラー値のように聞こえます。つまり、水色は 0x33ccff です。代わりに、R、G、または B のどれを設定するかを選択します。RGBValueint

  • パラメータの有効な値は 3 つだけですが、可能な値の範囲は完全に制限されていません。これはバグのレシピです。さらに悪いことに、個々の値はメソッド内でマジック ナンバーとして使用されます。

  • しかし、おそらく最も重要なのは、あなたが求めている「クリーン/クイックメソッド」は、まさにこのメソッドが提供しようとしている抽象化です! 色相を強調するメソッドを書いていますが、メソッドを短くするために、色相を強調するメソッドを求めています。意味がありません!

たとえば、次のように、色に対して実行したいことたくさんあるため、これを実行したいと思います。

public void Brighten(...) { ... }
public void Darken(...) { ... }
public void Desaturate(...) { ... }
public void Maximize(...) { ... }

などなど。そして、あなたはswitchすべての人のために声明を書くことを避けようとしています.

switch結構ですが、完全に排除しないでください。これはこのコードを記述する最も効率的読みやすい方法です。より重要なことは、それを多数ではなく1 つ に絞り込み、switch上記の他の問題を修正することです。intまず、列挙型を作成する代わりに、適切なパラメーター型から始めましょう。

public enum PrimaryColor { Red, Green, Blue };

ここで、合成色の原色の 1 つに対して実行したい多くのアクションがある可能性があるという考えから始めて、汎用メソッドを記述します。

protected void AdjustPrimaryColor(PrimaryColor pc, Func<byte, byte> adjustFunc)
{
    switch (pc)
    {
        case PrimaryColor.Red:
            internalColor.R = adjustFunc(internalColor.R);
        case PrimaryColor.Green:
            internalColor.G = adjustFunc(internalColor.G);
        default:
            Debug.Assert(pc == PrimaryColor.Blue,
                "Unexpected PrimaryColor value in AdjustPrimaryColor.");
            internalColor.B = adjustFunc(internalColor.B);
    }
}

このメソッドは短く、読みやすく、おそらく変更する必要はありません。それは良い、きれいな方法です。これで、個々のアクション メソッドを非常に簡単に記述できます。

public void Brighten(PrimaryColor pc)
{
    AdjustPrimaryColor(pc, v => v + 5);
}

public void Darken(PrimaryColor pc)
{
    AdjustPrimaryColor(pc, v => v + 5);
}

public void Desaturate(PrimaryColor pc)
{
    AdjustPrimaryColor(pc, v => 0);
}

public void Maximize(PrimaryColor pc)
{
    AdjustPrimaryColor(pc, v => 255);
}

これに対する(重要な)利点は次のとおりです。

  • 列挙型は、呼び出し元が失敗して無効なパラメーター値を渡すのを防ぎます。

  • 一般的なAdjust方法は読みやすいため、デバッグや保守が容易です。また、リフレクションベースまたはディクショナリベースのアプローチよりも優れたパフォーマンスを発揮します。ここでパフォーマンスが問題になる可能性はありませんが、主にこれを言っているのは、確かに悪化することはないということです.

  • switch繰り返しステートメントを書く必要はありません。個々の修飾子メソッドは、正確に 1 行です。

最終的には、どこかで実際にコードを書かなければならなくなりますが、コードはswitch、リフレクション、デリゲート、辞書などの混乱よりも、非常に単純なステートメントである方がよいでしょう。重要なのは、この作業を可能な限り一般化することです。可能; それを行ってその抽象化を作成したら、「実際の」作業を行うためのワンライナー メソッドを書き始めることができます。

于 2010-03-27T03:21:04.677 に答える
1

少し厄介ですが、次のように「参照によって」プロパティを渡すことができます。

    int ThisColor { get; set; }

    public void ChangeColor(Func<int> getter, Action<int> setter)
    {
        setter(getter() + 5);
    }

    public void SomeMethod()
    {
        ChangeColor(() => ThisColor, (color) => ThisColor = color);
    }

これはリフレクションよりもコストが低く、コンパイル時にチェックされます (リフレクションでは、GetProperty 呼び出しに文字列を渡す必要があり、後のリファクタリングで文字列名がプロパティ名と異なる可能性があります)。

于 2010-03-27T02:57:35.953 に答える
0

私があなたを正しく理解していれば、シンボル(またはプロパティ名) を取り、このシンボルによって定義された構造体のプロパティを変更するメソッドを書きたいと思います。これは C# では簡単に実現できません (もちろん、リフレクションを使用することもできますが...)。

Dictionaryプロパティの値を読み書きするためのデリゲートを含むことを使用して、同様のことを行うことができます。ただし、辞書を初期化する必要があるため、それでも少し長くなります。とにかく、コードは次のようになります。

var props = new Dictionary<string, Tuple<Func<Color, int>, Action<Color, int>>> 
  { "R", Tuple.Create(c => c.R, (c, r) => c.R = r),
    "G", Tuple.Create(c => c.G, (c, g) => c.G = g),
    "B", Tuple.Create(c => c.B, (c, b) => c.B = b) };

これにより、文字列 (プロパティの名前) をキーとして含むディクショナリと、各プロパティのゲッター デリゲートとセッター デリゲートを含むタプルが作成されます。ChangeColorメソッドは次のようになります。

public void ChangeColor(string propName) {
  var getSet = props[propName];    
  getSet.Item2(thisColor, getSet.Item1(thisColor) + 5);
}

およびという名前のプロパティではなく、Getプロパティ およびプロパティで独自の型を使用すると、コードが読みやすくなります。このソリューションはいくつかのシナリオで役立つ場合がありますが、ディクショナリを初期化するときにすべてのプロパティを明示的に一覧表示する必要があります。SetTupleItem1Item2

于 2010-03-27T02:07:18.120 に答える
0

大きなswitchステートメントになる可能性があると思われるものではなく、辞書を使用する傾向があるので、作成した場合

Dictionary<int,Func<int,int>> map = new Dictionary<int, Func<int, int>>();

辞書内の各項目は、新しい値を入力して返すことができます

あなたのメソッドを呼び出すことができます

        public int ChangeColor(int rgbValue)
    {
        return map[rgbValue](rgbValue);
    }

これにより、挿入した Rgb 値に固有のデリゲートが実行されます。デリゲートを割り当てるには、新しいエントリをマップに追加するだけです

map.Add(5,x => x+5);
于 2010-03-27T01:04:14.513 に答える
0

これはあなたが探しているものかもしれませんが、エラー処理を追加したいかもしれません。
public get; を使用すると、あらゆる種類のプロパティで機能します。設定します。メソッド。
必要に応じて、「マジック ストリング」の使用を減らす方法があります。

public static void ChangeProperty<T>(this object obj, string propertyName, Func<T,T> func)
{
    var pi = obj.GetType().GetProperty(propertyName);
    pi.SetValue(obj, func((T)pi.GetValue(obj, null)), null);
}
public void Change()
{
    thisColor.ChangeProperty<int>("R", (x) => x + 5);
}
于 2010-03-27T02:27:14.170 に答える
0

非常に単純化された例を示しているため、実際に何が起こっているのかを伝えるのはちょっと難しいです。

しかし、私が実際に読んでいるのは、メソッドのパラメーターの 1 つに基づいて、ローカル状態に対して可能な多くの変更の 1 つを実行するメソッドが必要だということです。

さて、操作は同じですか、それが行われていることを除いて?

最終的には、入力を目的の操作にマップすることを理解するコードが必要です。どの程度一般化できるかは、アクションがどれだけ類似しているかによって異なります (常に「プロパティに 5 を追加する」場合は、より多くの一般化オプションがあります...)。

あなたが持っているいくつかのオプションは次のとおりです。

  1. Color 構造体をカプセル化するクラスを作成します。
  2. ActionKev Hunter の提案に従って、s のルックアップ テーブルを使用します。
  3. switch ステートメントを記述します。
  4. 内部データで実行できる仮想メソッドを含むパラメーターを渡す (または単に Action<> を直接渡す) - ルックアップを回避する

と・・・本当にそれだけです。これらのどれが最も理にかなっているかは、おそらく実際のユースケース (実際には多くの情報を持っていません) に依存します。

于 2010-03-27T02:48:19.147 に答える