C# 如何在没有多个if语句的情况下检查条件?

C# 如何在没有多个if语句的情况下检查条件?,c#,android,if-statement,dry,C#,Android,If Statement,Dry,我正在用Xamarin为android开发一款游戏,但我有两个特别的部分非常枯燥(不要重复) 第一部分是当我想更改原声(音频播放)或背景时,根据级别,我对同一原声有三个不同的音高,对背景画布交替的背景也有三个不同的音高 对于这些方法,条件基于等于玩家所在级别的整数级别 示例代码 private void SetBackgrounds() { if (level == 5) { gameAreaCanvas.SetBackgroundResource(Resourc

我正在用Xamarin为android开发一款游戏,但我有两个特别的部分非常枯燥(不要重复)

第一部分是当我想更改原声(音频播放)或背景时,根据级别,我对同一原声有三个不同的音高,对背景画布交替的背景也有三个不同的音高

对于这些方法,条件基于等于玩家所在级别的整数级别

示例代码

private void SetBackgrounds()
{
    if (level == 5)
    {
        gameAreaCanvas.SetBackgroundResource(Resource.Drawable.LevelUpOneBackground);

    }
    else if (level == 10)
    {
        gameAreaCanvas.SetBackgroundResource(Resource.Drawable.LevelUpTwoBackground);

    }
    else if (level == 15)
    {
        gameAreaCanvas.SetBackgroundResource(Resource.Drawable.LevelUpThreeBackground);

    }
}
这同样适用于代码的不同部分,其中alot基于一个整型值,即级别。每次玩家将级别整数递增1,然后活动都会有检查整数级别的方法。代码正在工作,但显然效率很低,因为有很多重复的代码,只需稍加调整

例如,一个关卡看起来像这样

        if(level == 1) {

            levelDisplay.Text = "LEVEL 1";
            timer = new Timer();
            timer.Interval = 2000; /// DIFFERENT
            timer.Enabled = true;
            timer.Elapsed += Level1; /// DIFFERENT
            timer.Start();
        }
        ///LEVEL 2
        if (level == 2)
        {
            levelDisplay.Text = "LEVEL 2";
            timer = new Timer();
            timer.Interval = 2000; /// DIFFERENT
            timer.Enabled = true;
            timer.Elapsed += Level2; /// DIFFERENT
            timer.Start();
        }

有没有办法让这段代码不那么枯燥?非常感谢您的输入。

它们被称为switch语句,如下所示:

switch(level)
{
  case 1:
    doLevel1();
    break;
  case 2:
    doLevel2();
    break;
}
class Level
{
    readonly string levelName;

    Level( String levelName )
    {
        this.levelName = levelName;
    }

    void Setup()
    {
        levelDisplay.Text = levelName;
        SetupTimer();
    }

    virtual void SetupTimer()
    {
         //Default implementation
    }
}

class Level1: Level
{
    Level1() : Level( "LEVEL 1" ) 
    {
    }

    override void SetupTimer()
    {
        //Level1 implementation
    }
}
更多信息可以在这里找到:

你在找字典吗


第一部分可以浓缩如下:

canvas.SetBackgroundResource( level == 5? Resource.Drawable.LevelUpOneBackground : 
                              level = 10? Resource.Drawable.LevelUpTwoBackground :
                                          Resource.Drawable.LevelUpThreeBackground );
或者,更好的方法是创建一个字典,将级别编号映射到背景,这样您就可以:

gameAreaCanvas.SetBackgroundResource( resourcesFromLevels[level] );
简化第二部分更为复杂

在这种情况下,一种可能的解决方案是继承

您创建一个新的抽象
类级别
来表示游戏的一个级别,并为每个特定级别创建该类的子类。因此,您将拥有
类Level1:Level
类Level2:Level
,等等。基类有一个
Setup()
方法,该方法通过调用自身的可重写项来工作,每个可重写项都有一个默认实现,但是
级别的后代可以提供自己的实现

此外,并非所有内容都必须由可重写项处理。
Level
类可以接受一些构造函数参数,比如Level名称,然后每个子体可以为基类提供正确的Level名称。所以,它看起来是这样的:

switch(level)
{
  case 1:
    doLevel1();
    break;
  case 2:
    doLevel2();
    break;
}
class Level
{
    readonly string levelName;

    Level( String levelName )
    {
        this.levelName = levelName;
    }

    void Setup()
    {
        levelDisplay.Text = levelName;
        SetupTimer();
    }

    virtual void SetupTimer()
    {
         //Default implementation
    }
}

class Level1: Level
{
    Level1() : Level( "LEVEL 1" ) 
    {
    }

    override void SetupTimer()
    {
        //Level1 implementation
    }
}
我将使您的“级别”更面向对象:

public LevelObject
{
    public BackgroundResource BackgroundResource { get; set; }
    public string Text { get; set; }
    public double TimeInterval { get; set; }
    public double ElapsedInterval { get; set; }

    // constructors, methods, etc...
}
这样,您可以初始化“级别”集合,如
列表
,然后根据当前的
级别
,根据需要设置任何属性:

int level = // current level
List<LevelObject> levelObjectList =
    new List<LevelObject>
    {
        new LevelObject("LEVEL 1", 2000, Level1),
        new LevelObject("LEVEL 2", 2000, Level2),
        // etc...
    }
LevelObject levelObject = levelObjectList[level];

我会这样说:

首先,您需要一种枚举

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace ConsoleApp1
{
   public class MyEnumeration
   {
       #region Private Fields

       private readonly string _displayName;
       private readonly int _value;
       private readonly int _interval;
       private readonly Action _action;

       #endregion Private Fields

       #region Protected Constructors

       protected MyEnumeration()
       {
       }

       protected MyEnumeration(int value, string displayName, int interval, Action action)
       {
           _value = value;
           _displayName = displayName;
           _interval = interval;
           _action = action;
       }

       #endregion Protected Constructors

       #region Public Properties

       public string DisplayName
       {
           get { return _displayName; }
       }

       public int Value
       {
           get { return _value; }
       }

       public int Interval
       {
           get { return _interval; }
       }

       public Action Action
       {
           get { return _action; }
       }

       #endregion Public Properties

       #region Public Methods

       public static int AbsoluteDifference(MyEnumeration firstValue, MyEnumeration secondValue)
       {
           var absoluteDifference = Math.Abs(firstValue.Value - secondValue.Value);
           return absoluteDifference;
       }

       public static T FromDisplayName<T>(string displayName) where T : MyEnumeration, new()
       {
           var matchingItem = parse<T, string>(displayName, "display name", item => item.DisplayName == displayName);
           return matchingItem;
       }

       public static T FromValue<T>(int value) where T : MyEnumeration, new()
       {
           var matchingItem = parse<T, int>(value, "value", item => item.Value == value);
           return matchingItem;
       }

       public static IEnumerable<T> GetAll<T>() where T : MyEnumeration, new()
       {
           var type = typeof(T);
           var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);

           foreach (var info in fields)
           {
               var instance = new T();
               var locatedValue = info.GetValue(instance) as T;

               if (locatedValue != null)
               {
                   yield return locatedValue;
               }
           }
       }

       public int CompareTo(object other)
       {
           return Value.CompareTo(((MyEnumeration)other).Value);
       }

       public override bool Equals(object obj)
       {
           var otherValue = obj as MyEnumeration;

           if (otherValue == null)
           {
               return false;
           }

           var typeMatches = GetType().Equals(obj.GetType());
           var valueMatches = _value.Equals(otherValue.Value);

           return typeMatches && valueMatches;
       }

       public override int GetHashCode()
       {
           return _value.GetHashCode();
       }

       public override string ToString()
       {
           return DisplayName;
       }

       #endregion Public Methods

       #region Private Methods

       private static T parse<T, K>(K value, string description, Func<T, bool> predicate) where T : MyEnumeration, new()
       {
           var matchingItem = GetAll<T>().FirstOrDefault(predicate);

           if (matchingItem == null)
           {
               var message = string.Format("'{0}' is not a valid {1} in {2}", value, description, typeof(T));
               throw new ApplicationException(message);
           }

           return matchingItem;
       }

       #endregion Private Methods
   }
你可以像这样使用它:

private static void Main(string[] args)
{
    int level = 5;
    LevelEnum levelEnum = MyEnumeration.FromValue<LevelEnum>(level);

    levelDisplay.Text = levelEnum.DisplayName;
    timer = new Timer();
    timer.Interval = levelEnum.Interval;
    timer.Enabled = true;
    timer.Elapsed += levelEnum.Action;
    timer.Start();
}

internal static void Level1()
{
    // Action for Level 1
}

internal static void Level2()
{
    // Action for Level 2
}

internal static void Level3()
{
    // Action for Level 3
}
private static void Main(字符串[]args)
{
智力水平=5;
LevelEnum LevelEnum=MyEnumeration.FromValue(级别);
levelDisplay.Text=levelEnum.DisplayName;
定时器=新定时器();
timer.Interval=levelEnum.Interval;
timer.Enabled=true;
timer.appeased+=levelEnum.Action;
timer.Start();
}
内部静态空隙级别1()
{
//一级行动
}
内部静态空隙级别2()
{
//二级行动
}
内部静态空隙级别3()
{
//三级行动
}

如何使用开关箱?仅供参考,设置
timer.Enabled=true
timer.Start()相同。请看:@RufusL不知道,谢谢。这是我一直在研究的解决方案,但代码量似乎没有减少。有时我有多达25个级别,是编写25个开关案例的唯一解决方案吗?在您的情况下,最好的解决方案是switch语句,即使您必须编写25个开关案例。@fn5341我认为在这种情况下,最好的解决方案是使用映射(C#中的字典)。没有开关语句,干净而强大。这是一个有趣的解决方案!编辑:您是否对级别也有任何建议,或者切换大小写是唯一的其他选项?@Eli:借助
Tuple
(但是,自定义类将是更好的解决方案),您可以为多个(您的情况下为三个)值创建字典。请参阅我的编辑。我喜欢第一个解决方案,但您对元组有点迷茫……也许我需要进一步研究它。@Eli:
Tuple
是组合多个值的最简单(机械)方法;然而,它通常看起来很复杂,这就是为什么我建议使用自定义类。有趣的解决方案。试图找出一个解决方案,将计时器与此解决方案集成。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace ConsoleApp1
{
   public class MyEnumeration
   {
       #region Private Fields

       private readonly string _displayName;
       private readonly int _value;
       private readonly int _interval;
       private readonly Action _action;

       #endregion Private Fields

       #region Protected Constructors

       protected MyEnumeration()
       {
       }

       protected MyEnumeration(int value, string displayName, int interval, Action action)
       {
           _value = value;
           _displayName = displayName;
           _interval = interval;
           _action = action;
       }

       #endregion Protected Constructors

       #region Public Properties

       public string DisplayName
       {
           get { return _displayName; }
       }

       public int Value
       {
           get { return _value; }
       }

       public int Interval
       {
           get { return _interval; }
       }

       public Action Action
       {
           get { return _action; }
       }

       #endregion Public Properties

       #region Public Methods

       public static int AbsoluteDifference(MyEnumeration firstValue, MyEnumeration secondValue)
       {
           var absoluteDifference = Math.Abs(firstValue.Value - secondValue.Value);
           return absoluteDifference;
       }

       public static T FromDisplayName<T>(string displayName) where T : MyEnumeration, new()
       {
           var matchingItem = parse<T, string>(displayName, "display name", item => item.DisplayName == displayName);
           return matchingItem;
       }

       public static T FromValue<T>(int value) where T : MyEnumeration, new()
       {
           var matchingItem = parse<T, int>(value, "value", item => item.Value == value);
           return matchingItem;
       }

       public static IEnumerable<T> GetAll<T>() where T : MyEnumeration, new()
       {
           var type = typeof(T);
           var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);

           foreach (var info in fields)
           {
               var instance = new T();
               var locatedValue = info.GetValue(instance) as T;

               if (locatedValue != null)
               {
                   yield return locatedValue;
               }
           }
       }

       public int CompareTo(object other)
       {
           return Value.CompareTo(((MyEnumeration)other).Value);
       }

       public override bool Equals(object obj)
       {
           var otherValue = obj as MyEnumeration;

           if (otherValue == null)
           {
               return false;
           }

           var typeMatches = GetType().Equals(obj.GetType());
           var valueMatches = _value.Equals(otherValue.Value);

           return typeMatches && valueMatches;
       }

       public override int GetHashCode()
       {
           return _value.GetHashCode();
       }

       public override string ToString()
       {
           return DisplayName;
       }

       #endregion Public Methods

       #region Private Methods

       private static T parse<T, K>(K value, string description, Func<T, bool> predicate) where T : MyEnumeration, new()
       {
           var matchingItem = GetAll<T>().FirstOrDefault(predicate);

           if (matchingItem == null)
           {
               var message = string.Format("'{0}' is not a valid {1} in {2}", value, description, typeof(T));
               throw new ApplicationException(message);
           }

           return matchingItem;
       }

       #endregion Private Methods
   }
using System;

namespace ConsoleApp1
{
    internal class LevelEnum : MyEnumeration
    {
        public static readonly LevelEnum Level1 = new LevelEnum(1, "Level 1", 2000, Program.Level1);
        public static readonly LevelEnum Level2 = new LevelEnum(2, "Level 2", 3000, Program.Level2);
        public static readonly LevelEnum Level3 = new LevelEnum(3, "Level 3", 4000, Program.Level3);
        public static readonly LevelEnum Level4 = new LevelEnum(4, "Level 4", 5000, Program.Level4);
        public static readonly LevelEnum Level5 = new LevelEnum(5, "Level 5", 6000, Program.Level5);
        public static readonly LevelEnum Level6 = new LevelEnum(6, "Level 6", 7000, Program.Level6);
        public static readonly LevelEnum Level7 = new LevelEnum(7, "Level 7", 8000, Program.Level7);
        public static readonly LevelEnum Level8 = new LevelEnum(8, "Level 8", 9000, Program.Level8);

        public LevelEnum()
        {
        }

        protected LevelEnum(int value, string displayName, int interval, Action action) : base(value, displayName, interval, action)
        {
        }
    }
}
private static void Main(string[] args)
{
    int level = 5;
    LevelEnum levelEnum = MyEnumeration.FromValue<LevelEnum>(level);

    levelDisplay.Text = levelEnum.DisplayName;
    timer = new Timer();
    timer.Interval = levelEnum.Interval;
    timer.Enabled = true;
    timer.Elapsed += levelEnum.Action;
    timer.Start();
}

internal static void Level1()
{
    // Action for Level 1
}

internal static void Level2()
{
    // Action for Level 2
}

internal static void Level3()
{
    // Action for Level 3
}