无法与具有不同 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
.
我有两种类型都扩展了一个泛型基类型。这两种类型都没有额外的属性,只为抽象值赋值。当我尝试比较这两种类型时,使用 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
.