确定IEnumerable <t>中的任何元素是否可以强制转换为U </t>

时间:2012-09-22 18:02:27

标签: .net generics equals iequatable

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

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

1 个答案:

答案 0 :(得分:0)

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

听起来像你只是想确保盒装对象使用未装箱的值进行相等测试。你应该能够用这样的等于你想做的大部分事情:

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.IntersectExcept仅适用于相同类型的集合,因此如果类型为Object,则应该执行您想要的操作。

更新

值类型不能从基类派生。它们唯一的共同基础将始终只是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()));

结果为True,True和False。因此,显然两个对象可以“相等”,而不能在彼此之间进行转换。