如何解决仅在LINQ中的条件时选择
我不确定我是否有正确的标题,反正我试图将定界的字符串解析为Enum元素列表:
public enum MyEnum { Enum1,Enum2,Enum3 }
输入以下内容:
string s = "Enum2,enum3,Foo,";
我只想输出MyEnum
中存在的部分(忽略大小写):[MyEnum.Enum2,MyEnum.Enum3]
IEnumerable<MyEnum> sl =
s.Split(new char[] { ',',' ' },StringSplitOptions.RemoveEmptyEntries)
.Select(a => { if (Enum.TryParse(a,true,out MyEnum e)) return e; else return nothing ??? })
如果Select()
失败,如何从TryParse()
返回“无”?
我可以做这样的丑事:
IEnumerable<MyEnum> sl =
s.Split(new char[] { ',StringSplitOptions.RemoveEmptyEntries)
.Where(a => Enum.TryParse(a,out MyEnum dummy))
.Select(a => Enum.Parse(typeof(MyEnum),a,true));
无缘无故地进行两次解析工作,
但是我确定我缺少一些琐碎的东西。
如何以一种高效,优雅的方式完成此任务?
解决方法
如果您为enum
使用可为空的值,这将非常简单:
IEnumerable<MyEnum> sl =
s
.Split(new char[] { ',',' ' },StringSplitOptions.RemoveEmptyEntries)
.Select(a => { if (Enum.TryParse(a,true,out MyEnum e)) return (MyEnum?)e; else return null; })
.Where(x => x.HasValue)
.Select(x => x.Value);
您甚至可以进一步降低它:
.Select(a => Enum.TryParse(a,out MyEnum e) ? (MyEnum?)e : null)
或者您可以使用SelectMany
并避免使用空值:
IEnumerable<MyEnum> sl =
s
.Split(new char[] { ',StringSplitOptions.RemoveEmptyEntries)
.SelectMany(a => Enum.TryParse(a,out MyEnum e) ? new[] { e } : new MyEnum[] { });
,
即使Enum.TryParse
做得很繁重,它也不是最优的。会产生假阳性结果。
例如,如果您的s
字符串如下所示:
string s = "Enum2,enum3,Foo,4";
然后Enum.TryParse
将Enum2
,enum3
和4
转换为有效的MyEnum
实例。
为了从结果集中滤除4
,您必须调用Enum.IsDefined
。这是一个示例,如何将TryParse
和IsDefined
组合在一起:
s.Split(new[] { ',StringSplitOptions.RemoveEmptyEntries)
.Where(value => Enum.TryParse<MyEnum>(value,ignoreCase: true,out var parsedValue) && Enum.IsDefined(typeof(MyEnum),parsedValue))
.Select(value => (MyEnum)Enum.Parse(typeof(MyEnum),value,ignoreCase: true))
.ToList();
,
您可以使用可用于以下情况的LINQ聚合方法:
var sl= s.Split(new char[] { ',StringSplitOptions.RemoveEmptyEntries)
.Aggregate(new List<MyEnum> (),(List<MyEnum> enums,string a)=>
{
if (Enum.TryParse(a,out MyEnum e))
{
enums.Add(e);
}
return enums;
});
,
您可以将值-1
指定为无效的枚举值,从而用作所有无效字符串的占位符,并允许它们随后被排除。而且,这避免了多次解析字符串。
var invalidEnum = (MyEnum) (-1);
var sl = s.Split(new char[] {',' '},StringSplitOptions.RemoveEmptyEntries)
.Select(a =>
{
var isValid = Enum.TryParse(a,out MyEnum myEnum);
return isValid ? myEnum : invalidEnum;
})
.Where(a => a != invalidEnum);
如果显式定义,则枚举可能已经使用-1
(与默认最小值为零(0
)的原始示例不同,因此可以使用-1
)。为了最大程度地降低这种风险,可以使用以下值代替-1
:
var invalidEnum = (MyEnum) (int.MinValue);
// or
var invalidEnum = (MyEnum) (int.MaxValue);
如果仍然担心这些极不可能的值被采用,则可以找到该枚举未使用的下一个可用数字,并将其分配为无效的枚举:
var invalidEnum = (MyEnum) int.MinValue;
foreach(var number in Enumerable.Range(int.MinValue,int.MaxValue))
{
if (!Enum.IsDefined(typeof(MyEnum),number))
{
invalidEnum = (MyEnum) number;
break;
}
}
,
在将字符串s划分为子字符串之后,您只希望仅保留属于正确的myEnums的子字符串的枚举值。
您已经知道如何将原始字符串分为子字符串:
string s = ...
var subStrings = .Split(new char[] { ',StringSplitOptions.RemoveEmptyEntries);
使用Select尝试将每个subString解析为可为空的MyEnum。如果失败,则可为空没有值;否则,该空值将具有MyEnum值。
删除没有值的空值,然后选择其余值的值:
var result = subStrings.Select(subString => new
{
if (Enum.TryParse(subString,true out MyEnum parsedEnum)
{
return new Nullable<MyEnum>(parsedEnum);
}
else
{
return new Nullable<MyEnum>(null);
}
})
.Where(nullableEnum => nullableEnum.HasValue);
.Select(nullableEnum => nullableEnum.Value);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。