C# 减少重复代码

C# 减少重复代码,c#,readability,C#,Readability,我有一些关于颜色结构的代码,就像这样 public void ChangeColor() { thisColor.R = thisColor.R + 5; } 现在我需要创建一个方法,根据传递的内容更改不同的变量。下面是代码现在的样子 public void ChangeColor(int RGBValue) { switch(RGBValue) { case 1: thisColor.R = thisColor.R + 5;

我有一些关于颜色结构的代码,就像这样

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语句,并称之为一天,但这只是我的一个例子,实际函数相当长

我希望它看起来像这样:

public void ChangeColor(int RGBValue)
{
    thiscolor.RGBValue = thiscolor.RGBValue;
}
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) };
public void ChangeColor(string propName) {
  var getSet = props[propName];    
  getSet.Item2(thisColor, getSet.Item1(thisColor) + 5);
}
    int ThisColor { get; set; }

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

    public void SomeMethod()
    {
        ChangeColor(() => ThisColor, (color) => ThisColor = color);
    }
public void ChangeColor(int RGBValue)
{
    thisColor.{something-from-RGBValue} += 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
}

我倾向于使用字典,而不是我认为可能最终成为一个大型switch语句的东西,因此如果您创建了

Dictionary<int,Func<int,int>> map = new Dictionary<int, Func<int, int>>();
它将针对插入的Rgb值执行特定于代理的操作,要分配代理,只需向地图添加一个新条目即可

map.Add(5,x => x+5);

如果我理解正确,您希望编写一个方法,该方法采用一些符号(或属性名称),并使用此符号定义的值修改结构的属性。这在C#中不容易实现(当然可以使用反射,但是…)

您可以使用包含用于读取和写入属性值的委托的
字典
执行类似的操作。但是,这仍然有点长,因为您需要初始化字典。无论如何,代码可能如下所示:

public void ChangeColor(int RGBValue)
{
    thiscolor.RGBValue = thiscolor.RGBValue;
}
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) };
public void ChangeColor(string propName) {
  var getSet = props[propName];    
  getSet.Item2(thisColor, getSet.Item1(thisColor) + 5);
}
    int ThisColor { get; set; }

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

    public void SomeMethod()
    {
        ChangeColor(() => ThisColor, (color) => ThisColor = color);
    }
public void ChangeColor(int RGBValue)
{
    thisColor.{something-from-RGBValue} += 5;
}

如果您将自己的类型与
Get
属性和
Set
属性一起使用,而不是将
Tuple
与名为
Item1
Item2
的属性一起使用,则代码的可读性会更高。此解决方案在某些情况下可能很有用,但在初始化字典时仍需要显式列出所有属性。

这可能是您需要的,但您可能需要添加一些错误处理。
它将适用于任何类型的公共财产;并设置;方法。
如果你想,有办法减少使用“魔术弦”

公共静态void ChangeProperty(此对象对象对象,字符串属性名称,Func Func)
{
var pi=obj.GetType().GetProperty(propertyName);
pi.SetValue(obj,func((T)pi.GetValue(obj,null)),null);
}
公共空间更改()
{
thisColor.ChangeProperty(“R”,(x)=>x+5);
}

由于您给出了一个非常简单的示例,因此很难判断到底发生了什么

但是,我真正读到的是,您希望有一个方法,该方法将根据该方法的一个参数对局部状态执行一系列可能的修改

现在,除了对什么进行操作之外,操作是否相同

最终,您必须有一些能够理解将输入映射到所需操作的代码。可以概括的程度取决于动作的相似程度(如果总是“向属性添加5”,则您有更多的概括选项…)

您有以下几种选择:

  • 编写一个封装颜色结构的类
  • 按照Kev Hunter的建议,使用
    操作
    s的查找表
  • 写一个switch语句
  • 传入一个参数,该参数包含一个可以对内部数据执行的虚拟方法(或直接传入一个操作)——避免查找

  • 而且。。。就是这样,真的。其中哪一个最有意义可能更多地取决于您的实际用例(我们没有太多的信息),而不是其他任何东西。

    这有点尴尬,但您可以像这样“按引用”传递属性:

    public void ChangeColor(int RGBValue)
    {
        thiscolor.RGBValue = thiscolor.RGBValue;
    }
    
    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) };
    
    public void ChangeColor(string propName) {
      var getSet = props[propName];    
      getSet.Item2(thisColor, getSet.Item1(thisColor) + 5);
    }
    
        int ThisColor { get; set; }
    
        public void ChangeColor(Func<int> getter, Action<int> setter)
        {
            setter(getter() + 5);
        }
    
        public void SomeMethod()
        {
            ChangeColor(() => ThisColor, (color) => ThisColor = color);
        }
    
    public void ChangeColor(int RGBValue)
    {
        thisColor.{something-from-RGBValue} += 5;
    }
    
    intthiscolor{get;set;}
    公共void ChangeColor(Func getter、Action setter)
    {
    setter(getter()+5);
    }
    公共方法()
    {
    ChangeColor(()=>ThisColor,(color)=>ThisColor=color);
    }
    

    这比反射便宜,而且它是编译时检查的(使用反射,您必须将字符串传递给GetProperty调用,并且在以后的重构中字符串名称可能会与属性名称不同。)

    这绝对不是反射的目的。事实上,这里似乎有很多问题。让我们在此回顾一下-您希望更改以下方法:

    public void ChangeColor(int RGBValue)
    {
        switch(...)
        {
            case ...
            case ...
            case ...
        }
    }
    
    变成这样:

    public void ChangeColor(int RGBValue)
    {
        thiscolor.RGBValue = thiscolor.RGBValue;
    }
    
    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) };
    
    public void ChangeColor(string propName) {
      var getSet = props[propName];    
      getSet.Item2(thisColor, getSet.Item1(thisColor) + 5);
    }
    
        int ThisColor { get; set; }
    
        public void ChangeColor(Func<int> getter, Action<int> setter)
        {
            setter(getter() + 5);
        }
    
        public void SomeMethod()
        {
            ChangeColor(() => ThisColor, (color) => ThisColor = color);
        }
    
    public void ChangeColor(int RGBValue)
    {
        thisColor.{something-from-RGBValue} += 5;
    }
    
    这方面的问题是:

    • 该方法的名称,
      ChangeColor
      ,不能准确描述该方法的实际功能。也许这是匿名化的产物,但对于这种方法来说,这是一个可怕的名字

    • 参数“
      RGBValue
      ”不能准确描述参数是什么或做什么。名称
      RGBValue
      和类型
      int
      使其听起来像实际的RGB颜色值,即0x33ccff表示浅蓝色。相反,它选择设置R、G或B中的哪一个

    • 参数只有3个有效值,但可能值的范围完全不受限制。这是虫子的配方。更糟糕的是,单个值在方法中被用作幻数

    • 但也许最重要的是,您要求的“干净/快速方法”正是该方法声称提供的抽象您正在编写一种增强色调的方法,为了使方法简短,您要求。。。增强色调的方法。这没有道理

    我只能假设您想要这样做,因为您可能需要对颜色执行许多不同的操作,例如:

    public void Brighten(...) { ... }
    public void Darken(...) { ... }
    public void Desaturate(...) { ... }
    public void Maximize(...) { ... }
    
    等等等等。并且您试图避免为所有人编写
    switch
    语句

    可以,但不要完全取消
    开关
    ;到目前为止,它是