我有一些像这样的颜色结构的代码
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语句并称之为一天,但这只是我所拥有的一个例子,实际的功能很长。< / p>
我希望它看起来像这样:
public void ChangeColor(int RGBValue)
{
thiscolor.RGBValue = thiscolor.RGBValue;
}
所以基本上这个值会引用正在使用的变量。这有名字吗?这是反射的意义吗?或类似的东西......有办法做到这一点吗?
答案 0 :(得分: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
}
答案 1 :(得分:2)
这绝对是不的反映。事实上,这里似乎存在许多问题。我们在这里回顾一下 - 您想要更改以下方法:
public void ChangeColor(int RGBValue)
{
switch(...)
{
case ...
case ...
case ...
}
}
这样的事情:
public void ChangeColor(int RGBValue)
{
thisColor.{something-from-RGBValue} += 5;
}
问题是:
方法的名称ChangeColor
不会精确地描述该方法实际执行的操作。也许这是一个匿名化的工件,但不过它是这个方法的可怕名称。
参数RGBValue
不会准确地描述参数是什么或做什么。名称RGBValue
和类型int
使其听起来像实际的RGB颜色值,即浅蓝色的0x33ccff。相反,它选择设置R,G或B中的哪一个。
参数只有3个有效值,但可能值的范围完全不受限制。这是bug的秘诀。更糟糕的是,单个值在方法中用作幻数。
但也许最重要的是,你要求的“干净/快速方法”正是这种方法所要提供的抽象!你正在编写一种强化的方法色调,为了保持方法简短,你要求......一种强化色调的方法。这没有意义!
我只能假设您要这样做,因为您可能想要对Color执行许多不同的事情,例如:
public void Brighten(...) { ... }
public void Darken(...) { ... }
public void Desaturate(...) { ... }
public void Maximize(...) { ... }
依此类推。而且你试图避免为所有人写switch
语句。
很好,但不要完全消除switch
; 到目前为止是编写此代码的最有效的和可读方式!更重要的是将其提取到一个 switch
而不是很多,并解决上面提到的其他问题。首先,让我们从一个合理的参数类型开始,而不是int
- 创建一个枚举:
public enum PrimaryColor { Red, Green, Blue };
现在,从我们想要对复合颜色的一种主要颜色执行许多操作的想法开始,所以编写通用方法:
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
语句。每个单独的修饰符方法恰好是一行。
最终,某处,你实际上将不得不编写一些代码,我宁愿代码是一个非常简单的switch
语句而不是一塌糊涂的反思,代表,词典等等。关键是要尽可能地推广这项工作;一旦你完成了那个并创建了这个抽象,然后你就可以开始编写一个单行方法来完成“真正的”工作。
答案 2 :(得分: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调用,并且字符串名称可能在以后的重构中与属性名称分开。)
答案 3 :(得分: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);
答案 4 :(得分: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) };
这将创建一个字典,其中包含字符串(属性的名称)作为键,以及包含每个属性的getter委托和setter委托的元组。现在,您的ChangeColor
方法可能如下所示:
public void ChangeColor(string propName) {
var getSet = props[propName];
getSet.Item2(thisColor, getSet.Item1(thisColor) + 5);
}
如果您使用自己的Get
属性和Set
属性而不是Tuple
来使用名为Item1
和Item2
的属性,那么代码将更具可读性。此解决方案在某些情况下可能很有用,但您仍需要在初始化字典时明确列出所有属性。
答案 5 :(得分:0)
这可能是你要找的,你可能想要添加一些错误处理。
它适用于任何公共场所的财产;并设定;方法。
如果你想有办法减少使用“魔术字符串”。
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);
}
答案 6 :(得分:0)
嗯,因为你给出了一个非常简单的例子,所以很难说出真正发生了什么。
但是,我真正读到的是你想要一个方法,它将根据方法的一个参数对本地状态执行一些可能的修改。
现在,操作是否相同,除了它正在做什么?
最终,您必须拥有一些可以将输入映射到所需操作的代码。可以概括多少取决于行为的相似程度(如果它总是'向属性添加5'你有更多的泛化选项......)。
您有一些选择:
Action
s的查找表。而且......就是这样,真的。其中哪一个最有意义可能更多地取决于您的实际用例(我们并没有真正掌握大量信息)。