无法与具有不同 T 类型的两个不同通用对象进行比较

unable use compare to with two different generic object with different T types

我有两种类型都扩展了一个泛型基类型。这两种类型都没有额外的属性,只为抽象值赋值。当我尝试比较这两种类型时,使用 CompareTo 我得到一个一英里长的异常堆栈跟踪,它源于一个失败的类型案例。

如果我尝试使用泛型进行转换,是否可以比较这两种类型?

代码如下:

起始类型:

public interface IIdentifier : IEquatable<IIdentifier>, IComparable<IIdentifier>
{
    /// <summary>
    /// Numerical identifier
    /// </summary>
    long Id { get; }

    /// <summary>
    /// Provide the type of identifier.
    /// </summary>
    IdentifierType IdType { get; }
}

接下来两种类型扩展的基本标识符类型:

[DataContract]
public abstract class BaseIdentifier<T> : IIdentifier, IComparable<BaseIdentifier<T>>, IComparable, IEquatable<BaseIdentifier<T>> where T : class, IIdentifier
{
    #region Properties

    [DataMember(Order = 1)]
    public long Id { get; set; }

    [IgnoreDataMember]
    public abstract IdentifierType IdType { get; }

    #endregion
    #region Constructors

    protected BaseIdentifier(long id)
    {
        Id = id;
    }

    protected BaseIdentifier()
    {
    }

    #endregion

    #region IEquatable<IIdentifier> Members

    public bool Equals(IIdentifier other)
    {
        if (ReferenceEquals(other, null))
            return false;

        return this.IdType == other.IdType && this.Id == other.Id;
    }

    #endregion

    #region IComparable<IIdentifier> Members

    public int CompareTo(IIdentifier other)
    {
        int c = this.IdType.CompareTo(other.IdType);
        if (c != 0)
            c = this.Id.CompareTo(other.Id);
        return c;
    }

    #endregion
    #region IComparable<BaseIdentifier<T>> Members

    public int CompareTo(BaseIdentifier<T> other)
    {
        return Id.CompareTo(other.Id);
    }

    #endregion

    #region IComparable

    public int CompareTo(object obj)
    {
        return CompareTo(obj as BaseIdentifier<T>);
    }

    #endregion

    #region IEquatable<BaseIdentifier<T>> Members

    public bool Equals(BaseIdentifier<T> other)
    {
        if (ReferenceEquals(other, null))
            return false;

        return this.Id == other.Id;
    }

    #endregion

}

以下是在使用 BaseIdentifier<T> 函数尝试 CompareTo 时抛出异常的两种类型。

[DataContract]
public class Type1 : BaseIdentifier<Type1>
{
    [IgnoreDataMember]
    public override IdentifierType IdType
    {
        get { return IdentifierType.Type1; }
    }

    public Type1(long Id)
        : base(Id)
    {
    }

    public Type1()
    {
        // For serialization
    }
}

[DataContract]
public class Type2 : BaseIdentifier<Type2>
{
    [IgnoreDataMember]
    public override IdentifierType IdType
    {
        get { return IdentifierType.Type2; }
    }

    public Type1(long Id)
        : base(Id)
    {
    }

    public Type2()
    {
        // For serialization
    }
}

异常:

"Unable to cast object of type 'Domain.Contracts.Type2' 
to type 'Domain.Contracts.Type1`1[Domain.Contracts.Type1]'.""   
at Domain.Contracts.BaseIdentifier`1.CompareTo(Object obj) in 
C:\xsr\path\BaseIdentifier.cs:line 109\r\n   
at Xceed.Utils.Data.ObjectDataStore.CompareData(Object xData, Object yData)\r\n   
at Xceed.Utils.Data.ObjectDataStore.Compare(Int32 xRecordIndex, Int32 yRecordIndex)\r\n   
at Xceed.Wpf.DataGrid.DataGridCollectionViewSort.Compare(Int32 xDataIndex, Int32 yDataIndex)\r\n   
at Xceed.Utils.Collections.IndexWeakHeapSort.Sort(Int32 length)\r\n   
at Xceed.Wpf.DataGrid.DataGridCollectionViewGroupRoot.SortRootRawItems(SortDescriptionInfo[] sortDescriptionInfos, List`1 globalRawItems)\r\n   
at Xceed.Wpf.DataGrid.DataGridCollectionView.SortItems(SortDescriptionInfo[] sortDescriptionInfos)\r\n   
at Xceed.Wpf.DataGrid.DataGridCollectionView.ExecuteSourceItemOperation(DeferredOperation deferredOperation, Boolean& refreshForced)\r\n   
at Xceed.Wpf.DataGrid.DeferredOperationManager.Process(Boolean processAll)\r\n   
at Xceed.Wpf.DataGrid.DataGridCollectionViewBase.DeferRefreshHelper.ProcessDispose(DataGridCollectionViewBase collectionView)\r\n   
at Xceed.Wpf.DataGrid.DataGridCollectionViewBase.DeferRefreshHelper.Dispose(Boolean disposing)\r\n   
at Xceed.Wpf.DataGrid.DataGridCollectionViewBase.DeferRefreshHelper.System.IDisposable.Dispose()\r\n   
at Xceed.Wpf.DataGrid.DataGridSortDescriptionCollection.DeferResortDisposable.Dispose()\r\n   
at Xceed.Wpf.DataGrid.ColumnSortCommand.Disposer.Dispose(Boolean disposing)"

这与泛型在 C# 中的工作方式有关。泛型语法实际上只是为了让您的生活更轻松,但您必须记住,更改泛型类型确实会使它成为 不同的类型 。所以 BaseIdentifier<Type1>BaseIdentifier<Type2> 是完全不同的类型。你在代码中只写一次,但在编译时它们是分开的。

弄清楚如何准确地实现您的目标可能很复杂。根据您上面的示例,最简单的选择是使其实现 IComparible<IIdentifier> 而不是使用通用类型。

您的 CompareTo(ojbect) 代码试图将 BaseIdentifier<Type1> 转换为 BaseIdentifier<Type1>,这是不合法的。

由于您无法比较具有不同泛型参数的对象,看来您应该更改

public int CompareTo(object obj)
{
    return CompareTo(obj as BaseIdentifier<T>);
}

public int CompareTo(object obj)
{
    return CompareTo(obj as IIdentifier);
}

以便您绑定到采用 接口 而不是通用类型的重载。

您也可以考虑重载 Equals(object),将其重定向到 Equals(IIdentifier),这意味着您 需要重载 GetHashCode.