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

时间:2016-06-15 21:49:17

标签: c# generics comparison

我有两种类型都扩展了通用基类型。两种类型都没有其他属性,只为赋值赋值。当我尝试比较这两种类型时,使用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

}

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

[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)"

2 个答案:

答案 0 :(得分:0)

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

弄清楚如何准确实现你的目标可能很复杂。基于上述示例的最简单选项是使其实现IComparible<IIdentifier>而不是使用泛型类型。

答案 1 :(得分:0)

您的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