使用Enumerable.Empty <string>()

时间:2015-09-29 21:02:11

标签: c# .net linq

我希望Enumerable.Empty<string>()返回一个空字符串数组。相反,它似乎返回一个具有单个null值的数组。这打破了DefaultIfEmpty之类的其他LINQ运算符,因为可枚举实际上并不是空的。这似乎没有在任何地方记录,所以我想知道我是否遗漏了某些东西(概率为99%)。

GameObject Class

 public GameObject(string id,IEnumerable<string> keywords) {
        if (String.IsNullOrWhiteSpace(id)) {
            throw new ArgumentException("invalid", "id");
        }
        if (keywords==null) {
            throw new ArgumentException("invalid", "keywords");
        }
        if (keywords.DefaultIfEmpty() == null) { //This line doesn't work correctly.
            throw new ArgumentException("invalid", "keywords");
        }
        if (keywords.Any(kw => String.IsNullOrWhiteSpace(kw))) {
            throw new ArgumentException("invalid", "keywords");
        }

        _id = id;
        _keywords = new HashSet<string>(keywords);
    }

测试

    [TestMethod]
    [ExpectedException(typeof(ArgumentException))]
    public void EmptyKeywords() {
        GameObject test = new GameObject("test",System.Linq.Enumerable.Empty<string>());
    }

3 个答案:

答案 0 :(得分:8)

看起来你期待这种情况:

keywords.DefaultIfEmpty() == null

评估为true。但是,如果源序列为空,DefaultIfEmpty将返回包含元素类型(在本例中为string)的默认值的单例序列。因此,它将返回包含null的序列。这本身不是null,但条件会返回false

答案 1 :(得分:1)

您误解了public static WebClient webclient = new WebClient(); public static string GetIP() { string externalIP = ""; externalIP = webclient.DownloadString("http://checkip.dyndns.org/"); externalIP = (new Regex(@"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}")) .Matches(externalIP)[0].ToString(); return externalIP; } 的实施,这是它的实施from the reference source

DefaultIfEmpty

所以它的作用是如果public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source) { return DefaultIfEmpty(source, default(TSource)); } public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source, TSource defaultValue) { if (source == null) throw Error.ArgumentNull("source"); return DefaultIfEmptyIterator<TSource>(source, defaultValue); } static IEnumerable<TSource> DefaultIfEmptyIterator<TSource>(IEnumerable<TSource> source, TSource defaultValue) { using (IEnumerator<TSource> e = source.GetEnumerator()) { if (e.MoveNext()) { do { yield return e.Current; } while (e.MoveNext()); } else { yield return defaultValue; } } } 不为空它只返回IEnumerable<T>,如果IEnumerable<T>为空则返回新的IEnumerable<T>,其中包含一个对象它的值为IEnumerable<T>。它将永远不会返回default(T),这是您的测试所测试的。如果你想测试这个,你需要做

null

然而,这将导致多次评估if(keywords.DefaultIfEmpty().First() == null) 。我会放弃LINQ,就像LINQ方法一样,并且做得很长(这也消除了IEnumerable<string>内部的额外评估。)

new HashSet<string>(keywords)

这使得您只能在 public GameObject(string id,IEnumerable<string> keywords) { if (String.IsNullOrWhiteSpace(id)) { throw new ArgumentException("invalid", "id"); } if (keywords==null) { throw new ArgumentException("invalid", "keywords"); } _keywords = new HashSet<string>(); using (var enumerator = keywords.GetEnumerator()) { if (e.MoveNext()) { do { if(e.Current == null) throw new ArgumentException("invalid", "keywords"); _keywords.Add(e.Current); } while (e.MoveNext()); } else { throw new ArgumentException("invalid", "keywords"); } } _id = id; } 上循环一次。

答案 2 :(得分:0)

这会解决您的问题吗?

 public GameObject(string id, IEnumerable<string> keywords) {
    if (String.IsNullOrWhiteSpace(id)) {
        throw new ArgumentException("invalid", "id");
    }
    if (keywords == null || !keywords.Any()
            || keywords.Any(k => String.IsNullOrWhiteSpace(k))) {
        throw new ArgumentException("invalid", "keywords");
    }

    _id = id;
    _keywords = new HashSet<string>(keywords);
}

*通过@ScottChamberlain&amp;的建议改进了代码@ginkner