[英]Select only if condition in LINQ
我不確定我是否有這個 Q 的正確標題。無論如何,我正在嘗試將分隔字符串解析為 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 ??? })
如果TryParse()
失敗,如何從Select()
返回“無”?
我可以做一件丑陋的事情,比如:
IEnumerable<MyEnum> sl =
s.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
.Where(a => Enum.TryParse(a, true, 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, true, out MyEnum e) ? (MyEnum?)e : null)
或者您可以使用SelectMany
並避免可空值:
IEnumerable<MyEnum> sl =
s
.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
.SelectMany(a => Enum.TryParse(a, true, 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, true, 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, true, 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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.