我已经在我的一个项目中启用了C# 8.0 non-nullable reference types功能,但是现在我不清楚如何表示丢失的数据。
例如,我正在读取一个文件,其行是用冒号分隔的键/值对。有时,一行上有多个冒号。在这种情况下,第一个冒号之前的文本是键,其余部分是值。我解析每一行的代码如下:
public (string key, string value) GetKeyValue(string line)
{
var split = line.Split(':');
if (split.Length == 2)
return (split[0].Trim(), split[1].Trim());
else if (split.Length > 2)
{
var joined = string.Join(":", split.ToList().Skip(1));
return (split[0].Trim(), joined.Trim());
}
else
{
Debug.Print($"Couldn't parse this into key/value: {line}");
return (null, null);
}
}
这是做什么的:如果我们只有一个冒号,请返回键和值。如果有多个,则在第一个冒号之后加入其余文本,然后返回键和值。否则,我们将没有冒号并且无法解析它,因此返回一个空元组。 (让我们假设这最后一种情况可以合理地发生;我不能仅仅抛出它并称其为错误文件。)
很明显,除非我将声明更改为
,否则最后一行会收到可空警告。 public (string? key, string? value) GetKeyValue(string line)
现在在F#中,我将仅使用Option类型,在非冒号的情况下,我将返回None。
但是C#没有Option类型。我可以返回("", "")
,但对我来说,这似乎不比null好。
在这种情况下,不使用null来说“我什么都没找到”的好方法是什么?
答案 0 :(得分:0)
您可以通过仅返回一个标志来包括结果是否解析成功:
public class Result
{
private Result(){}
public bool Successful {get;private set;} = false;
public string Key {get; private set;} = string.Empty;
public string Value {get; private set;} = string.Empty;
public static Successful(string key, string value)
{
return new Result
{
Successful = true,
Key = key,
Value = value
};
}
public static Failed()
{
return new Result();
}
}
public Result GetKeyValue(string line){
return Result.Failed();
}
然后您可以像使用它
var result = GetKeyValue("yoda");
if(result.Successful)
{
// do something...
}
或者,您可以返回2种不同的类型并使用模式匹配
答案 1 :(得分:0)
实际上,我现在意识到问题的一部分在于我的方法正在做两件事:
因此返回值必须同时表明是否和键,以及什么键和值。
我可以通过单独做第一项来简化:
bool HasKey(string line)
{
var split = line.Split(':');
return split.Length >= 2;
}
然后在我发布的方法中,如果没有键,我可以抛出并说需要首先由HasKey过滤行。
答案 2 :(得分:0)
放下我的功能性思维上限,惯用的返回类型为IEnumerable<(string?,string?)>
。对您的代码的唯一更改是将return
更改为yield return
,并在找不到任何内容的情况下删除了return
语句。
public IEnumerable<(string? key, string? value)> GetKeyValue(string line)
{
var split = line.Split(':');
if (split.Length == 2)
return (split[0].Trim(), split[1].Trim());
else if (split.Length > 2)
{
var joined = string.Join(":", split.ToList().Skip(1));
yield return (split[0].Trim(), joined.Trim());
}
else
{
Debug.Print($"Couldn't parse this into key/value: {line}");
}
}
然后,呼叫者可以选择几种方法来处理响应。
如果他们想检查密钥是否是老式的eway,请执行以下操作:
var result = GetKeyValue(line).SingleOrDefault();
if (!result.HasValue) HandleKeyNotFound();
如果他们希望在找不到密钥的情况下抛出异常,则可以这样做:
var result = GetKeyValue(line).Single();
如果他们只是想保持安静,可以使用ForEach
,如果找到它们,它将使用键和值;如果没有,则不执行任何操作:
foreach (var result in GetKeyValue(line)) DoSomething(result.Item1, result.Item2);
此外,出于价值考虑,我建议您使用KeyValuePair而不是元组,因为它可以明确传达字段的目的。