使用enum作为方法参数

时间:2018-06-16 19:56:32

标签: c# .net design-patterns

我有以下方法可以下载一组商品价格或许可证价格并将其存储在本地硬盘上。 两者之间的唯一区别是输入列表,它指示应该查询哪些项目。 该应用程序正在部署为clickonce应用程序,因此文件的存储区别于调试到部署版本。

    private const string PRICEFILE = "Resources\\prices.xml";
    private const string RATEFILE = "Resources\\rates.xml";
    private const string INPUTFILE = "Resources\\ItemsList.txt";
    private const string INPUTFILELICENSE = "Resources\\Licenses.txt";
    private const string LICENSEFILE = "Resources\\Licenses.xml";

   public string getFromInventoryTableOnServer(InventoryTypeEnum type)
    {
        string _input = "";
        string _output = "";
        // Get items from items file in resources
        if (ApplicationDeployment.IsNetworkDeployed)
        {
            if (type.Equals(InventoryTypeEnum.Prices))
            {
                _input = ApplicationDeployment.CurrentDeployment.DataDirectory + @"\" + INPUTFILE;
                _output = ApplicationDeployment.CurrentDeployment.DataDirectory + @"\" + PRICEFILE;
            }
            else if (type.Equals(InventoryTypeEnum.Licences))
            {
                _input = ApplicationDeployment.CurrentDeployment.DataDirectory + @"\" + INPUTFILELICENSE;
                _output = ApplicationDeployment.CurrentDeployment.DataDirectory + @"\" + LICENSEFILE;
            }
        }
        else
        {
            if (type.Equals(InventoryTypeEnum.Prices))
            {
                _input = INPUTFILE;
                _output = PRICEFILE;
            }
            else if (type.Equals(InventoryTypeEnum.Licences))
            {
                _input = INPUTFILELICENSE;
                _output = LICENSEFILE;
            }
        }


        // Read file
        List<string> items = new List<string>();
        using (var sr = new StreamReader(_input))
        {


            while (!sr.EndOfStream)
            {
                items.Add(sr.ReadLine().Split(new[] { Environment.NewLine }, StringSplitOptions.None)[0]);
            }

        }

        // Connection to database and table
        List<InventTableDW> it;
        using (AXDataContext ax = new AXDataContext())
        {
            var table = ax.GetTable<InventTableDW>();

            // Query AX for item info, specially prices
            var query =
                from p in table
                where items.Contains(p.ItemID) && p.ItemGroupID == "100"
                orderby p.ItemID
                select p;

            try
            {
                it = query.ToList();
            }
            catch (Exception e)
            {
                return e.Message;
            }
        }


        // Write to the price file
        try
        {
            using (var sw = new StreamWriter(_output))
            {
                {
                    var ser = new XmlSerializer(typeof(List<InventTableDW>));
                    ser.Serialize(sw, it);
                }
            }
        }
        catch (Exception e)
        {
            return e.Message;
        }
        return "";
    }

enum InventoryTypeEnum
{
    Prices,
    Licences
}

我对目前的实施并不感到自豪,因为它看起来有点凌乱。你有任何改进建议吗?

非常感谢!

3 个答案:

答案 0 :(得分:1)

字典是摆脱ifswitch语句的好方法,但我不太喜欢Sam Axe提出的嵌套字典解决方案。我的解决方案只使用一个Dictionary

我创建了一个简单的类,它将用作Dictionary的键,覆盖GetHashCodeEquals方法:

internal class Key
{
    public readonly bool IsNetworkDeployed { get; }
    public readonly InventoryTypeEnum InventoryType { get; }

    public Key(InventoryTypeEnum inventoryType, bool isNetworkDeployed=false)
    {
        IsNetworkDeployed = isNetworkDeployed;
        InventoryType = inventoryType;
    }

    protected bool Equals(Key other)
    {
        return IsNetworkDeployed == other.IsNetworkDeployed && 
               InventoryType == other.InventoryType;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;

        return Equals((Key) obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (IsNetworkDeployed.GetHashCode() * 397) ^ (int) InventoryType;
        }
    }
}

而且,正如Sam所建议的那样,一个坚持路径的课程:

public class FilePaths
{
    public string InputPath { get; set; } = string.Empty;
    public string OutputPath { get; set; } = string.Empty;
}

初始化Dictionary

private readonly Dictionary<Key, FilePaths> _pathsDictionary = new Dictionary<Key, FilePaths>
{
    {
        new Key(InventoryTypeEnum.Licences, isNetworkDeployed: true),
        new FilePaths {
            InputPath = $@"{ApplicationDeployment.CurrentDeployment.DataDirectory}\{INPUTFILELICENSE}",
            OutputPath = $@"{ApplicationDeployment.CurrentDeployment.DataDirectory}\{LICENSEFILE}"
        }
    },
    {
        new Key(InventoryTypeEnum.Prices, isNetworkDeployed: true), 
        new FilePaths {
            InputPath = $@"{ApplicationDeployment.CurrentDeployment.DataDirectory}\{INPUTFILE}",
            OutputPath = $@"{ApplicationDeployment.CurrentDeployment.DataDirectory}\{PRICEFILE}"
        }
    },
    {
        new Key(InventoryTypeEnum.Licences, isNetworkDeployed: false), 
        new FilePaths {
            InputPath = INPUTFILELICENSE,
            OutputPath = LICENSEFILE
        }
    },
    {
        new Key(InventoryTypeEnum.Prices, isNetworkDeployed: false), 
        new FilePaths {
            InputPath = INPUTFILE,
            OutputPath = PRICEFILE
        }
    }
};

使用代码:

public string GetFromInventoryTableOnServer(InventoryTypeEnum type)
{
    var key = new Key(type, ApplicationDeployment.IsNetworkDeployed);
    FilePaths paths = _pathsDictionary[key];

    // remaining code here ...
}

答案 1 :(得分:0)

查找行中的某些内容可能会使代码更多&#34;漂亮&#34;。虽然对可维护性的影响可能是可疑的。每当路径发生变化时,您都需要记住更新_pathMap变量。不应该是一个大问题......你必须在某处改变它们

另外,我并不关心bool密钥,但我尽量让它尽可能接近原来的功能。 bool没有立即传达意图。如果可能的话,我建议将其更改为枚举。

private class FilePaths {
    public FilePaths(string inputPath, string outputPath) { 
        InputPath = inputPath;
        OutputPath = outputPath;
    }
    public string InputPath {get; set; } = string.Empty;
    public string OutputPath {get; set; } = string.Empty;
}

enum InventoryTypeEnum {
    Prices,
    Licences
}

private const string PRICEFILE = "Resources\\prices.xml";
private const string RATEFILE = "Resources\\rates.xml";
private const string INPUTFILE = "Resources\\ItemsList.txt";
private const string INPUTFILELICENSE = "Resources\\Licenses.txt";
private const string LICENSEFILE = "Resources\\Licenses.xml";

private Dictionary<bool, Dictionary<InventoryTypeEnum, FilePaths>> _pathMap = 
    new Dictionary<bool, Dictionary<InventoryTypeEnum, FilePaths>>() {
        { true, { InventoryTypeEnum.Prices, 
                  new FilePaths(
                      ApplicationDeployment.CurrentDeployment.DataDirectory + @"\" + INPUTFILE,
                      ApplicationDeployment.CurrentDeployment.DataDirectory + @"\" + PRICEFILE
                  ) 
        } },
        { true, { InventoryTypeEnum.Licences, 
                  new FilePaths(
                      ApplicationDeployment.CurrentDeployment.DataDirectory + @"\" + INPUTFILELICENSE,
                      ApplicationDeployment.CurrentDeployment.DataDirectory + @"\" + LICENSEFILE
                  ) 
        } },
        { false, { InventoryTypeEnum.Prices, 
                  new FilePaths(
                      INPUTFILE,
                      PRICEFILE
                  ) 
        } },
        { false, { InventoryTypeEnum.Licenses, 
                  new FilePaths(
                      INPUTFILELICENSE,
                      LICENSEFILE
                  ) 
        } }
    }

public string getFromInventoryTableOnServer(InventoryTypeEnum type) {
    FilePaths paths = _pathMap[ApplicationDeployment.IsNetworkDeployed][type];
    // paths.InputPath and paths.OutputPath should now hold the correct values.

    //  ... rest of function ...
}

答案 2 :(得分:0)

首先,将嵌套的if移动到一个返回ValueTuple<string, string>的单独方法。从那里你有几个选择,我想建议一个带开关。

我认为最好首先检查枚举,以防将来增长,然后检查布尔值。像这样:

enum Animal
{
    Fish,
    Dog,
    Zebra
}

string GetLabel(bool isAwesome, Animal animal)
{
    switch (animal)
    {
        case Animal.Fish:
            return isAwesome ? "awesome fish" : "not so awesome fish";
        case Animal.Dog:
            return isAwesome ? "super awesome dog" : "awesome dog";
        case Animal.Zebra:
            return isAwesome ? "awesome zebra" : "normal zebra";
        default:
            return "is this even an animal?";
    }
}

并不是说这比其他答案中提出的嵌套Dictionary更有效。