将自定义选项传递给函数的最佳方法

时间:2013-04-20 16:38:08

标签: c# design-patterns refactoring

我正在编写REST API的包装器。因此,每当我从服务器检索项目时,我只需要使用参数(在uri中)。我现在这样做的方式工作得很好,但我觉得必须有另一种优雅的方式,可能用enum或其他东西。

我不喜欢我需要'知道'Dictionary类型为string的选项是什么。我尝试使用Dictionary<EnumType, string>,但我有多种enum。另外,我不确定如何将EnumType(键)映射到适当的值。

基本上,我尽量避免使用magic关键字。

这是我的部分代码:

public string GetUnreadItems()
{
    var options = new Dictionary<string, string>();
    options.Add("ItemType", "Unread");
    options.Add("SortBy", "Latest");
    // GetItemsBasedOn(options);
}

public string GetAllItems()
{
    var options = new Dictionary<string, string>();
    options.Add("ItemType", "All");
    // GetItemsBasedOn(options);
}

public string GetItemsBasedOn(Dictionary<string, string> options)
{
    // Do request here based on options passed
    // and return the result to caller function 
}

编辑: 这就是我想要实现的http://getpocket.com/developer/docs/v3/retrieve

我想实施选项sortdetailTypecontentTypeFavoriteState。每个选项都有自己的选项,但一次只能选择一个。

1 个答案:

答案 0 :(得分:2)

有几种方法可以改善您当前的设计。我不同意我要向您呈现的解决方案是理想的解决方案,但鉴于您已经确定您想要使用enum,我认为您将满足于此解决方案。

您可以做的是定义标有enum属性的[Flags]。为枚举中的每个标志分配一个2的幂。如果要组合选项以创建单个选项,请使用bitwise or,就像我在前面的示例中使用名为“All”的标志一样:

[Flags]
public enum GetItemOptions
{
    Read = 0x1,
    Unread = 0x2,
    All = 0x1 | 0x2,
    SortByOldest = 0x4,
    SortByLatest = 0x8
}

从您的代码示例中,第一个调用现在将如下所示:

GetItemsBasedOn(GetItemOptions.Unread | GetItemOptions.SortByLatest);

第二个看起来像这样:

GetItemsBasedOn(GetItemOptions.All);

为了启用此设计,您需要调整GetItemsBasedOn方法签名,以便它指定GetItemOptions枚举类型的参数。以下是如何处理不同设置的示例。

public static void GetItemsBasedOn(GetItemOptions getItemOption)
{
    if (getItemOption.HasFlag(GetItemOptions.SortByOldest) && getItemOption.HasFlag(GetItemOptions.SortByLatest))
        throw new ArgumentException("I can't sort by both...");

    if (getItemOption.HasFlag(GetItemOptions.Read))
    {
        Console.WriteLine("READ");
    }

    if (getItemOption.HasFlag(GetItemOptions.Unread))
    {
        Console.WriteLine("UNREAD");
    }

    if (getItemOption.HasFlag(GetItemOptions.SortByOldest))
    {
        Console.WriteLine("SORT BY OLDEST");
    }
    else if (getItemOption.HasFlag(GetItemOptions.SortByLatest))
    {
        Console.WriteLine("SORT BY NLATEST");
    }
}

我认为您对逐位操作知之甚少,因此我使用Enum.HasFlag方法尽可能地简化了代码示例,该方法只检查给定的GetItemOptions枚举已指定标志。

在使用RegexOptions EnumerationControlStyles Enumeration

之前,您可能已经露出了这种模式的见证人

更新

我建议你为每个参数创建一个enum并定义一个这样的类:

public class PocketDataRequest
{
    public State? State { get; set; }
    public Favourite? Favourite { get; set; }
    public ContentType? ContentType { get; set; }
    public Sort? Sort { get; set; }
    public DetailType? DetailType { get; set; }

    public Dictionary<string, string> ToPostData()
    {
        return GetType().GetProperties()
                        .Where(p => p.GetValue(this, null) != null)
                        .ToDictionary(p => p.Name, 
                                      p => p.GetValue(this, null).ToString());
    }
}

这将利用以下语法:

PocketDataRequest pocketDataRequest = new PocketDataRequest();
pocketDataRequest.State = State.Unread;
pocketDataRequest.Sort = Sort.Newest;
GetItemsBasedOn(pocketDataRequest.ToPostData());

在我的实现ToPostData方法中,我使用LINQ和Reflection,这只是因为我很懒。您需要手动评估每个enum值,尤其是当您要将enum名称更改为更合适的名称时。此外,如果您尝试传递标题为favorite的参数,我的代码将失败。这是因为favorite取数字“0”或“1”。这不是一个大问题,因为你可以做的就像这样定义enum

public enum Favourite
{
    UnfavouritedItems = 0,
    FavouritedItems = 1
}

然后只需转换值(Int32)并将该值添加到Dictionary<string, string>NameValueCollection