代码之家  ›  专栏  ›  技术社区  ›  We Are All Monica

将一对键->值映射传递给函数的优雅语法?

  •  1
  • We Are All Monica  · 技术社区  · 16 年前

    int val = myObject.getValue<int>("FieldName", { { "", 0 }, { "INF", int.MaxValue } });
    

    字段名在那里,以便以后发生错误时可以检索它。对于本例来说,这一点很重要,因为函数需要采用不相关的第一个参数。

    但是,我很难想出一个优雅且类型安全的语法来提供这个功能(以上基于集合初始值设定项的语法只有在我坚持的情况下才有效) new FieldValueMappingCollection<int> { ... } 在那里)。


    所以,我知道的选择是:
    myObject.getValue<int>("FieldName", new FieldValueMappingCollection<int> { { "", 0 }, { "INF", int.MaxValue } });
    

    myObject.getValue<int>("FieldName", "", 0, "INF", int.MaxValue);
    

    其中getValue params object[]

    一定有更好的方法吧?

    6 回复  |  直到 16 年前
        1
  •  1
  •   djdd87    16 年前

    下面的课程怎么样:

    public class MyObject<T>
    {
    
        public T GetValue(string fieldName, params MyObjectMap<T>[] mappings)
        {
           // Do whatever you need to do
        }
    
        public MyObjectMap<T> Map(string from, T to)
        {
            return MyObjectMap<T>.Map(from, to);
        }
    
    }
    
    public class MyObjectMap<T>
    {
    
        private MyObjectMap(string from, T to) { }
    
        public static MyObjectMap<T> Map(string from, T to)
        {
            return new MyObjectMap<T>(from, to);
        }
    
    }
    

    你可以这样使用:

    private void Foo()
    {
        MyObject<int> myObject = new MyObject<int>();
        myObject.GetValue("FieldName",
            myObject.Map("", 0),
            myObject.Map("INF", int.MaxValue));
    }
    

    而且完全是类型安全的。

        2
  •  3
  •   drharris    16 年前

    Dictionary<String, Int32> 或者别的什么。在课堂上设置一次,然后简单地把字典传进来。因为您正在创建一个API,所以这是一种更简洁、更具表现力的方式来声明您的意图,而不是使用元组。字典是为这些类型的操作构建的,您的用户应该能够很容易地理解方法的意图。元组更不容易理解,尤其是在处理简单的键值映射时。

    此外,如果您想动态初始化,它可以提供更好的初始化: http://msdn.microsoft.com/en-us/library/bb531208.aspx

        3
  •  1
  •   Timwi    16 年前

    传递一个代表怎么样:

    myObject.GetValue<int>("FieldName", value =>
    {
        if (string.IsNullOrEmpty(value))
            return 0;
        if (value == "INF")
            return int.MaxValue;
        throw new InvalidInputException();
    });
    

    • 这比一对一的值映射支持更广泛的可能性。
    • 如果它变得复杂,您可以使它成为自己的方法,而不需要在这里内联它。
    • 它是完全类型安全的。
    • InvalidInputException 与…沟通 GetValue<>() 你不能处理输入。

    • 冗长的。。。
    • 如果 已经认为有效,例如,您不能使其拒绝1。
    • 如果 呼叫代表
        4
  •  0
  •   mqp    16 年前

    通常的方法是:

    myObject.getValue<int>("FieldName",
        Tuple.Create("", 0),
        Tuple.Create("INF", int.MaxValue));
    

    使用接受params数组的函数,以及这些字段项的.NET元组或您自己的“元组”类。

    恐怕在保留静态输入的同时,在C语言中没有更简洁的方法了。集合初始值设定项语法不允许您不指定类型而逃脱惩罚。

        5
  •  0
  •   Diego Jancic    16 年前

    我不会发送参数的信息。我会使用流利的语法,比如:

    object.With("", 0)
          .With("INF", int.MaxValue)
          .Get<int>("FieldName");
    

    您可以更改方法名称,使其看起来像您想要的那样。其他选择可以是:

    object.GetValueUsing("", 0)
          .AndUsing("INF", int.MaxValue)
          .Of<int>("FieldName");
    

    object.WithParameter("", 0)
          .AndParameter("INF", int.MaxValue)
          .GetValue<int>("FieldName");
    

    如果你不知道如何创建一个流畅的界面,只要在谷歌上搜索“c#creating fluent interface”,你就会看到大量的示例。

        6
  •  0
  •   Dr. Wily's Apprentice    16 年前

    赞成的意见:

    • 使用匿名类型的简单紧凑语法

    • 可能会做很多反思
    • 密钥仅限于有效标识符,即不允许使用特殊字符

    GetValue方法有4个参数:

    1. 字符串值为“”时的默认值
    2. 无法通过值映射识别正确值时使用的分析委托

    (似乎我需要在列表后面加一行,以避免弄乱代码格式)

        public T GetValue<T>(string fieldName, T @default, object valueMap, Converter<string, T> parse)
        {
            T value;
            string literalString = null; // read string from file
    
            if (string.IsNullOrEmpty(literalString))
                return @default;
            else
            {
                var map = ToDictionary<T>(valueMap);
                // attempt to look up the corresponding value associated with literalString
                if (map.TryGetValue(literalString, out value))
                    return value;
                else
                    // literalString does not match any value in the value map,
                    // so parse it using the provided delegate
                    return parse(literalString);
            }
        }
    
        public static Dictionary<string, T> ToDictionary<T>(object valueMap)
        {
            // Use reflection to read public properties and add them as keys to a
            // dictionary along with their corresponding value
            // The generic parameter enforces that all properties
            // must be of the specified type,
            // otherwise the code here can throw an exception or ignore the property
            throw new NotImplementedException();
        }
    
    
            // usage
    
            int field1 = myObject.GetValue("Field1", 0, new { one = 1, two = 2, TheAnswer = 42, min = int.MinValue, max = int.MaxValue, INF = int.MaxValue }, int.Parse);
    
            double field2 = myObject.GetValue("Field2", 0.0, new { PI = Math.PI, min = double.MinValue, max = double.MaxValue }, double.Parse);