C#避免多个SWITCH语句 .net

8

请原谅我的愚笨,因为我正在学习C# / .NET的复杂性。

假设我有三个类,每个类都有多个静态属性(为了举例,假设有超过三个)

 CLASS FOO

    public static A
    { 
       get / set A;
    }   
    public static B
    {
       get / set B;
    }   
    public static C
    {
       get / set C;
    }   

 CLASS BAR
     {
        get / set A;
     }
    public static B
    {
       get / set B;
    }   
    public static C
    {
       get / set C;
     }   

 CLASS YOO
     {
        get / set A;
     }
    public static B
    {
       get / set B;
     }   
    public static C
    { 
       get / set C;
    }   

我需要在另一个类中多次更新每个类的一个或多个静态属性......如何避免编写多个类似于这样的SWITCH语句...

 public void updateVarx(string class, string varx)
 {
   string y = 'class'
   SWITCH (y)
   {
      case FOO:
       FOO.A = Varx;
       break;
      case BAR:
       BAR.A = Varx;
       break;
      case YOO:
       YOO.A = Varx;
      break;
   }
 }

当我想要更新变量B的值时,需要再添加一个函数:

 public void updateVary(string class, string vary)
 {
   string y = 'class'
   SWITCH (y)
   {
     case FOO:
      FOO.B = Vary;
      break;
     case BAR:
      BAR.B = Vary;
      break;
    case YOO:
      YOO.B = Vary;
      break;
   }
 }

因为我不想要它们的多个实例...但是除此之外,它们是一组固定证券的状态变量。 - CraigJSte
“请原谅我偶尔的愚蠢” 可能是我今天早上遇到的最好的短语。它非常有趣,而且没有贬低的意味 :) - BoltClock
@CraigJSte:我认为他指的是我们所说的代码异味。 - BoltClock
可能是一个接口,但如果它们只是状态变量,为什么不创建一个新类来保存这些变量,并让FOO、BAR和YOO引用该类呢? - Pete
这三个类是三种固定的证券(具体来说是货币对),自动交易系统会在多次更新订单状态、价格、日期等(加上其他20多个变量)... 当我启动订单输入和订单退出代码时,这些类需要更新保存每种证券订单信息的类中的静态变量...请帮我设计更好的方案...谢谢。 - CraigJSte
显示剩余7条评论
6个回答

4

由于您正在学习.net/c#,我想我应该警告您,在面向对象编程中使用静态属性可能不是正确的方式。

静态属性是全局状态,很危险。如果您最终使用多线程代码,必须非常小心。如果您只需要一个实例,请实例化一个,但不要在类上创建静态属性,除非您有一个相当好的理由将它们添加进去(我现在想不出任何好的理由)。

事实上,在设计良好的面向对象代码中,您也应该尽量减少if、switch、getter或setter的使用。

假设您需要在类上实现不同的行为,可以这样做。

Interface ISecurity {
  void UpdateVarX(int value);
  void UpdateVarY(int value);
  int GetValueX();
  int GetValueX();
}

class Foo:ISecurity {
  // Implement methods of the interface
}

class Bar:ISecurity {
  // Implement methods of the interface
}

class Yoo:ISecurity {
  // Implement methods of the interface
}

// This class is the class that uses your other classes
class Consumer 
{
  private ISecurity sec;

  public Consumer(ISecurity sec) {
    sec.UpdateVarX(25);
  }
}

或者像您的例子一样,如果所有静态类具有相同的属性:
public class Settings {
  public int A {get; set;}
  public int B {get; set;}
  public int C {get; set;}
}

public class NeedsToUseOtherClass {
  public NeedsToUseOtherClass() {
    Settings foo = new Settings();
    Settings bar = new Settings();
    Settings yoo = new Settings();

    foo.setA(25);
  }
}

@Martin - 你的写法真的很误导人。但我想你的意思是“你不应该使用if/switch来确定对象的类型,然后执行给定的操作。”(对吗?) - Josh M.
1
@Josh M. 是的,但通常情况下,如果您有很多嵌套的if语句、switch语句,导致缩进很多,那么您的代码可能存在问题。 - Martin
@Martin。是的,同意。关于你发布的链接,对于任何了解编程基础的人来说,这不是显而易见的吗?简直不敢相信这个“运动”存在!;-)谢谢。 - Josh M.
@Martin,顺便说一下,我在类中从静态更改为实例化...然后使用了一个开关来识别接口,完成了...谢谢! - CraigJSte
@Martin,实际上,我认为您比我多1或2个问题。 但是我正在学习。 Antifcampaign是一个很好的方式,在基础水平上开始引起某人的注意,如if语句-谁会想到呢?? 我想我是@Josh所说的不懂编程基础的团体中的一员... :( 哦,没关系! - CraigJSte
显示剩余4条评论

2

也许我没有理解问题,但如果你的所有类都具有完全相同的属性,则可以将对象(FOO、BAR或YOO)传递到UpdateVarx或UpdateVary方法中,并实现一个接口? 大致如下:

public class FOO : IHasStatus
{
    public A
    { 
       get / set A;
    }   
    public B
    {
       get / set B;
    }   
    public C
    {
       get / set C;
    }
} 

public void updateVarx(IHasStatus someObject, string varx)
{
    someObject.A = varx;
}
public void updateVary(IHasStatus someObject, string vary)
{
    someObject.B = vary;
}

@Pete,天哪,我想你搞定了!!(额外加分 - 谁说过这句话,是福尔摩斯)? - CraigJSte
@codenaked 这是真的,我复制和粘贴了他的代码。但我认为状态属性不必是静态的,对吗?我想我很难理解它们为什么一开始就是静态的。 - Pete
@Pete,你告诉我 - 这些类是从订单例程调用的,它们对固定数量的证券执行更新到多个状态变量..如果我只实例化一个实例,我不需要它们是静态的...但我每分钟运行1000次订单例程..所以我想确保没有重复的状态存在于某个地方 - 非常非常重要。 - CraigJSte
@Pete,实际上我认为你的问题的答案是肯定的,除了我只有一个 FOO 实例,一个 BAR 实例和一个 YOO 实例,但它们都共享相同的静态属性,这些属性在不同的时间更新等等... - CraigJSte
@craigjste 很好!我很高兴它为你解决了问题。有时候,看起来最复杂的问题其实有着最简单的解决方法。 - Pete
显示剩余10条评论

1

如果您不需要具体的类,您可以这样抽象出逻辑:

public class Status {
    public string A {
        get; set;
    }

    public string B {
        get; set;
    }

    public string C {
        get; set;
    }
}

public static class StatusManager {
    private static Dictionary<string, Status> statusMap = new Dictionary<string,Status>();

    public static Status GetStatus(string name) {
        Status status;
        if (!statusMap.TryGetValue(name, out status))
            statusMap[name] = status = new Status();
        return status;
    }

    public static void SetStatus(string name, Status status) {
        statusMap[name] = status;
    }

    public static void UpdateVarx(string name, string varx) {
        GetStatus(name).A = varx;
    }

    // ...
}

@Pete - 你是在问我还是在问@CraigJSte? :-) - CodeNaked
@pete 我不确定它是否有效,但我喜欢它!仔细看后,它很可能有效,但我需要复习一下DICT的用法。不过这很好... - CraigJSte
1
@craigjste 这看起来是一个不错的开始。如果有什么问题,只需在MSDN.com上熟悉一下字典的使用即可。在这里,字典是你最不用担心的问题 =P - Pete
1
@Pete = 你觉得我会这么轻易地放过你吗?现在告诉我你认为真正的问题是什么... :) - CraigJSte
1
@craigjste 老实说,我不确定问题是什么,但我知道它不是字典的问题。对我来说,似乎可以通过接口轻松解决,但我可能误解了问题的领域。 - Pete

0

如果你喜欢使用JavaScript解决多个switch case的问题,比如this

你可以将这些switch处理程序封装成操作(Actions),并将它们放入字典中。

例如:(来源于这里

   public class SwitchCase : Dictionary<string,Action>
    {
        public void Eval(string key)
        {
            if (this.ContainsKey(key))
              this[key]();
            else
             this["default"](); 
        }
    }


    //Now, somewhere else

            var mySwitch = new SwitchCase
            {
                { "case1",  ()=>Console.WriteLine("Case1 is executed") },
                { "case2",  ()=>Console.WriteLine("Case2 is executed") },
                { "case3",  ()=>Console.WriteLine("Case3 is executed") },
                { "case4",  ()=>Console.WriteLine("Case4 is executed") },
                { "default",()=>Console.WriteLine("Default is executed") },
            };

            mySwitch.Eval(c);

嗯,我会考虑这个@world,谢谢,我希望能得到一个“更简单”的答案(是的,我故意加了引号),这可能意味着我不够聪明,也可能意味着我只是简单 :) - CraigJSte

0
以下代码使用了各种技巧,除非你有非常好的理由,否则在生产代码中并不推荐使用。
using System;
using System.Linq;

namespace ConsoleApplication1
{
    static class Program
    {
        private static void SetStaticProperty(string className, string propName, string varx)
        {
            //This sucks, I couldnt find the namespace with easily through reflection :(
            string NAMESPACE = "ConsoleApplication1";
            Type t = Type.GetType(NAMESPACE + "." + className);
            t.GetProperties().Where(p => p.Name == propName).First().SetValue(null, varx, null);
        }

        public static void updateVarx(string className, string varx)
        {
            SetStaticProperty(className, "A", varx);
        }

        public static void updateVary(string className, string vary)
        {
            SetStaticProperty(className, "B", vary);
        }

        static void Main(string[] args)
        {
            updateVarx("Foo", "FooAstring");
            updateVarx("Bar", "BarAstring");
            updateVarx("Yod", "YodAstring");
            updateVary("Foo", "FooBstring");
            updateVary("Bar", "BarBstring");
            updateVary("Yod", "YodBstring");

            Console.WriteLine(Foo.A);
            Console.WriteLine(Foo.B);
            Console.WriteLine(Bar.A);
            Console.WriteLine(Bar.B);
            Console.WriteLine(Yod.A);
            Console.WriteLine(Yod.B);
            Console.ReadLine();
        }
    }

    class Foo
    {
        public static string A { get; set; }
        public static string B { get; set; }
        public static string C { get; set; }
    }

    class Bar
    {
        public static string A { get; set; }
        public static string B { get; set; }
        public static string C { get; set; }
    }

    class Yod
    {
        public static string A { get; set; }
        public static string B { get; set; }
        public static string C { get; set; }
    }
}

有任何原因给我踩分吗?我在顶部警告说这不是一段很好的代码,我只是展示了一种可能性。 - Sanjeevakumar Hiremath
抱歉,但我不得不给您的帖子投反对票。这不是解决问题的正确方法,正如您自己所说,“在生产代码中并不推荐使用”。 - bic
是的,那就是我说的。我认为这种技术在许多情况下仍然很有用。它是展示可能性的一种方式。 - Sanjeevakumar Hiremath
我知道你在一开始就发出了警告,但这是一个初学者试图学习C#。再次强调,我很少会点踩,但我认为这个答案虽然能够工作,但在这种情况下并不正确,抱歉 :-) - bic
抱歉让大家失望了 :-) - bic

0

你可以使用字典作为配置,避免使用switch语句 创建一个字典,并按以下方式添加数据进行映射

//Have dictionary setted up
Dictionary<string, dynamic> m_Dictionary = new Dictionary<string, dynamic>();
m_xmlDictionary.Add("classA",FOO);
m_xmlDictionary.Add("classB",BAR);
m_xmlDictionary.Add("classC",BAR);
//Have dictionary setted up


//change the function as below
public void updatevarx(string class, string varx)
{
    m_Dictionary[class].A=varx // Replaced switch statement
}

//while calling use
updatevarx("classC","abc!");// This will assign BAR.A with abc!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接