我正在开发一个API,它将从文件读取字符串值并允许类型转换。我还需要它提供一种将给定字符串值“映射”到所需类型的特定值的方法。这看起来像这样:
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[]
。
必须有更好的方法来做到这一点,对吗?
答案 0 :(得分:3)
更好的方法是使用Dictionary<String, Int32>
或其他。在类中设置一次,然后简单地传入字典。由于您正在创建API,这是一种更清晰,更富表现力的方式来声明您的意图而不是使用元组。为这些类型的操作构建字典,您的用户应该能够轻松理解该方法的意图。元组不太容易理解,特别是当你处理简单的键值映射时。
此外,如果您想要即时初始化,它可以实现更好的初始化: http://msdn.microsoft.com/en-us/library/bb531208.aspx
答案 1 :(得分:1)
以下课程怎么样:
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 :(得分:1)
如何传递委托:
myObject.GetValue<int>("FieldName", value =>
{
if (string.IsNullOrEmpty(value))
return 0;
if (value == "INF")
return int.MaxValue;
throw new InvalidInputException();
});
<强>优点:强>
InvalidInputException
与GetValue<>()
进行通信,告知您无法处理输入。<强>缺点:强>
GetValue<>()
仅在无法处理输入时调用该委托,则您不能使用此方法来覆盖GetValue<>()
已认为有效的值,例如你不能拒绝-1。GetValue<>()
在之前调用委托,它会自行处理,那么每次抛出异常都会有性能损失。答案 3 :(得分:0)
通常的做法是:
myObject.getValue<int>("FieldName",
Tuple.Create("", 0),
Tuple.Create("INF", int.MaxValue));
使用一个带有params数组的函数,以及这些字段条目的.NET元组或你自己的“元组”类。
我担心在保留静态类型的同时C#中没有更简洁的方法。集合初始化程序语法不会让您忘记指定类型。
答案 4 :(得分:0)
我不会将信息作为参数发送。我会使用流利的语法,如下所示:
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#创建流畅的界面”,你就会有大量的样本。
答案 5 :(得分:0)
我会考虑做类似下面的例子。
优点:
缺点:
GetValue方法有4个参数:
(看起来我在列表后面需要一行以避免弄乱代码格式化)
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);