0

在较新版本的 .net 中,有许多扩展方法可以接受IEnumerable<T>IEnumerable. 一种这样的方法是OfType<TResult>返回一个仅包含原始序列的元素的可枚举,这些元素可以转换为指定的类型TIEnumerable无论原始列表的类型和目标类型如何,此方法都使用非泛型处理原始列表的所有项目,非常愉快地完成了任务。如果原始列表是一个IEnumerable<int>并且TResultint,它将获取原始列表的每个项目作为非泛型object,然后将其转换,即使它可以只使用原始列表IEnumerator<int>。如果原始列表是一个IEnumerable<int>并且TResultStringBuilder,它同样会通过装箱原始列表中的所有项目,即使它们都不可能被转换为目标类型。

编写一个采用 anIEnumerable<TSrc>并将其转换为 an的方法有多难IEnumerable<TResult>,有效地处理原始枚举中的所有项目都保证出现在后者中的情况,或者源枚举数的类型将暗示后者将为空(假设IEnumerable类型支持的所有变体都将返回相同的项目序列)?可以肯定的是,人们不会经常尝试将一个序列强制转换为它已经拥有的类型,但是拥有一个具有多个类型参数的泛型类并不少见,这些类型参数有时会重叠,有时不会重叠。

4

1 回答 1

0

IEquatable<T>.Equals应该与Object.Equals覆盖一致。我不确定直接使用IEquatable<T>直接提供任何价值。

在我看来,您只是想确保装箱的对象使用未装箱的值进行相等测试。你应该能够用这样的 equals 做大部分你想做的事情:

private static bool Equals<T1, T2>(T1 first, T2 second)
{
    // if either are boxed, try Equals with unboxed values (dynamic)
    if (typeof(T2) == typeof(object) && second.GetType().IsValueType)
    {
        dynamic dsec = second;
        if (typeof(T1) == typeof(object) && second.GetType().IsValueType)
        {
            dynamic dfir = first;
            return Equals(dfir, dsec);
        }
        return Equals(first, dsec);
    }
    if (typeof(T1) == typeof(object) && second.GetType().IsValueType)
    {
        dynamic dfir = first;
        Equals<dynamic, T2>(dfir, second);
    }
    // neither are boxed, just fall back to their Equals overrides...
    var t = Object.Equals(first, second);
    return t;
}

Enumerable.Intersect并且Except只使用相同类型的集合,所以如果类型是Object它应该做你想要的。

更新:

值类型不能从基类派生。它们唯一的共同基础永远只有对象,这意味着如果你想比较两种不同的值类型,而不是专门使用一种知道你想比较的两种类型的方法,你总是必须装箱至少一个值——哪个Enumerable.IntersectExcept不'无论如何都接受。所以不写不同的方法是不可能的。

更新 2:

假设如果两种类型不能在彼此之间(或一种到另一种)之间转换,这意味着它们永远不会相等,这是一个糟糕的假设。例如:

public struct One
{
    public int Value;
    public override int GetHashCode()
    {
        return Value.GetHashCode();
    }
}

public struct Two
{
    public int Value;
    public override bool Equals(object obj)
    {
        if (obj is Two) return this == (Two)obj;
        if (obj is One) return this.Equals((One)obj);
        return base.Equals(obj);
    }

    public bool Equals(One one)
    {
        return one.Value == Value;
    }

    public static bool operator==(Two one, Two two)
    {
        return one.Value == two.Value;
    }

    public static bool operator !=(Two one, Two two)
    {
        return !(one == two);
    }
    public override int GetHashCode()
    {
        return Value.GetHashCode();
    }
}

// ...

    Console.WriteLine(two.Equals(one));
    Console.WriteLine(two.Equals((Object)one));
    Console.WriteLine(two.GetType().IsAssignableFrom(one.GetType()) || one.GetType().IsAssignableFrom(two.GetType()));

结果为真、真和假。因此,显然两个对象可以“相等”,但不能相互转换。

于 2012-09-23T18:19:20.167 回答