【问题标题】:c# Cast string as IEnumerable<T>c# 将字符串转换为 IEnumerable<T>
【发布时间】:2017-10-27 14:11:52
【问题描述】:

我有这个功能:

public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable)  
{  
    return iterable.Distinct();  
}

这适用于除字符串之外的任何 IEnumerable,我必须使用此调用对其进行测试:

Assert.AreEqual("ABCDAB", UniqueInOrder("AAAABBBCCDAABBB"));

断言失败:

Expected is <System.String>, actual is <System.Linq.Enumerable+<DistinctIterator>c__Iterator10`1[System.Char]>
  Values differ at index [4]

我也尝试过类似的方法:

public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable)
{
    return "abc";
}

但是我有一个编译器错误:

Cannot implicitly convert type 'string' to 'System.Collections.Generic.IEnumerable<T>'

我怎么可能用字符串调用函数但不能返回字符串?类型还是一样的 IEnumerable

有什么想法吗? 谢谢!

编辑: Distinct() 错了,我改成这样:

public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable)
{
    List<T> result = new List<T>();
    foreach (var c in iterable.ToList())            
        if (result.LastOrDefault() == null || !result.LastOrDefault().Equals(c))
            result.Add(c);              
    return result;
}

现在所有的测试都通过了!谢谢!

【问题讨论】:

  • Distinct() 不会返回多个相同的字母,那么您为什么期望返回值?至于第二个问题,你不能从那个方法返回一个字符串,因为一个字符串只满足IEnumerable&lt;char&gt;,而不满足任何其他类型T
  • UniqueInOrder 很好。 Assert.AreEqual() 需要字符串。
  • “我怎么可能用字符串调用函数,但我不能返回字符串” 你把参数和返回类型混为一谈了。字符串是IEnumerable&lt;char&gt;,但它不能转换为任何类型的IEnumerable&lt;T&gt;
  • @Matthew 是一个字符串 definitely is an IEnumerable&lt;char&gt;,但对于除 char 之外的任何 T,它都不是 IEnumerable&lt;T&gt;
  • 无论哪种方式 IEnumerable&lt;T&gt;IEnumerable&lt;char&gt; 都不相等。

标签: c# string generics casting ienumerable


【解决方案1】:

实际上,字符串是字符的集合,因此当您使用UniqueInOrder("AAAABBBCCDAABBB") 时,您实际上调用的是UniqueInOrder&lt;char&gt;,而不是UniqueInOrder&lt;string&gt;。因此该方法的返回值也将是IEnumerble&lt;char&gt;,而不仅仅是字符串。

因此,您应该将方法返回值与字符集合进行比较,例如:

CollectionAssert.AreEqual(new[] { 'A', 'B', 'C', 'D', 'A' 'B', 'Ä' }, UniqueInOrder(...));

或更简单:

CollectionAssert.AreEqual(expected.ToCharArray(), UniqueInOrder(...));

但即便如此,您的测试也会失败,因为Distinct 会过滤掉所有重复项。

当您想检查两个序列是否完全相同时,您可以改用SequenceEqual

var equal = firstColl.SequenceEqual(second);

编辑:显然,您正在尝试删除序列中的所有双倍字符。你可以使用这个:

public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable) where T : IEquatable<T>
{
    T previous = default(T);
    foreach (var t in iterable)
    {
        if (!t.Equals(previous))
            yield return t;
        previous = t;
    }
}

现在您可以调用它并将其与您的预期输出进行比较,例如:

var actual = new String(UniqueInOrder("AABBCCDDAABB").ToArray());
var expected "ABCDAB";
Assert.AreEqual(expected, actual);

【讨论】:

  • 但是测试还是不会通过,因为Distinct()不关心顺序,它会返回{ 'A', 'B', 'C', 'D' }...
  • "该方法的返回值也将是 IEnumerble,而不仅仅是字符串。" - string 一个IEnumerable&lt;char&gt;类型的表达式。
  • 我认为应该是if (!t.Equals(previous))
【解决方案2】:

Himbrombeere 解释了为什么断言由于类型问题而失败。但它也会失败,因为Distinct 不符合您的预期。它将删除所有重复的字母,而不仅仅是那些连续的。所以它将返回ABCD 而不是ABCDAB

这会做你想做的事,断言会通过:

public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable, EqualityComparer<T> comparer = null)
{
    if (comparer == null) comparer = EqualityComparer<T>.Default;
    bool first = true;
    T lastItem = default(T);
    foreach(T thisItem in iterable)
    {
        if (first || !comparer.Equals(thisItem, lastItem))
        {
            first = false;
            yield return thisItem;
        }
        lastItem = thisItem;
    }
}

Assert.AreEqual("ABCDAB", String.Conat(UniqueInOrder("AAAABBBCCDAABBB")));

【讨论】:

    【解决方案3】:

    关于你问题的第一部分,你的断言失败的原因是因为.Distinct()

    打电话时

    UniqueInOrder("AAAABBBCCDAABBB");
    

    这个方法:

    private IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable)    
    {
        return iterable.Distinct();
    }
    

    将返回{'A', 'B', 'C', 'D'}

    但是这个方法:

    private IEnumerable<T> RemovesDupesInOrder<T>(IEnumerable<T> iterable)
    {
        List<T> result = new List<T>();
    
        T last = default(T);
        iterable.ToList().ForEach(t =>
        {
            if (t.Equals(last) == false)
            {
                last = t;
                result.Add(t);
            }
        });
    
        return result;
    }
    

    将返回{'A', 'B', 'C', 'D', 'A', 'B'}

    注意:t.Equals(last) 可能会也可能不会按照您对引用类型的期望实现。

    【讨论】:

    • .ToList().ForEach(...) 将循环您的数据两次...使用普通的foreach 语句。
    • 是的,你是对的。这是一个很好的观点。我将保留我的代码。希望人们会阅读您的评论,这将是一个很好的提醒。
    【解决方案4】:

    UniqueInOrder("AAAABBBCCDAABBB") 返回"ABCD",因为这些是字符串中的不同字符。这不等于 "ABCDAB",区别在于第 5 个字符(或代码术语中的第 4 个字符,因为 am IEnumerable 是 0-indexed)。

    这正是断言失败告诉你的。字符在索引为 4 的可枚举元素中的元素不同。具体来说,在第二个参数中,索引不存在。 Assert.AreEqual("ABCD", UniqueInOrder("AAAABBBCCDAABBB")) 可以正常工作

    return "abc" 的情况下会出现编译器错误,因为字符串"abc" 不是通用IEnumerable。如果您传入 IEnumerable&lt;int&gt; 类型将不兼容,因此它必须是编译器错误

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-24
      • 2014-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-02
      相关资源
      最近更新 更多