我的类的C#泛型列表包含找不到我的实例的方法

我们有几个类用于我们的CMS,我正在努力使等式工作,所以我可以检查通用列表是否包含一个项目。我们有一些继承层,我将在下面给你看。在此之下,我将向您展示一些与我的期望相反的示例代码。如果你看到我做错了什么,请告诉我。我已经减少了以下示例,只是为了向您展示相关的部分。我的实际课程要大得多,但我认为这是你需要看到的一切。 IBaseTemplate.cs
public interface IBaseTemplate {
  bool Equals(IBaseTemplate other);
  string GUID { get; }
}
BasePage.cs
public class BasePage : System.Web.UI.Page, IBaseTemplate, IEquatable<IBaseTemplate> {

  // code to define properties, including GUID

  // various constructors
  public BasePage(string GUID) { 
    this.GUID = GUID;
  }

  // interface methods
  public bool Equals(IBaseTemplate other) {
    return (this.GUID == other.GUID);
  }

}
LandingPage.cs
public class LandingPage : BasePage {
  // a bunch of extra properties and method specific to LandingPage
  // but NO definition for Equals since that's taken care of in BasePage

  public LandingPage(string GUID) : base(GUID) {}
}
SamplePage.aspx.cs
var p1 = new LandingPage("{3473AEF9-7382-43E2-B783-DB9B88B825C5}");
var p2 = new LandingPage("{3473AEF9-7382-43E2-B783-DB9B88B825C5}");
var p3 = new LandingPage("{3473AEF9-7382-43E2-B783-DB9B88B825C5}");
var p4 = new LandingPage("{3473AEF9-7382-43E2-B783-DB9B88B825C5}");

var coll = new List<LandingPage>();
coll.Add(p1);
coll.Add(p2);
coll.Add(p3);

p1.Equals(p4);     // True, as expected
coll.Contains(p4); // False, but I expect True here!
我希望
coll.Contains(p4)
返回
true
因为即使
p1
p4
是不同的实例,
BasePage
的继承
Equals
方法比较their11ѭ所要求的
GUID
属性。我在这里错过了什么吗? 我查看了List(T)的Contains方法的文档,我正在实现
IEquatable<T>.Equals
,其中
T
IBaseTemplate
。     
已邀请:
您还需要覆盖
Object.Equals(Object)
- 请参阅此链接。     
我敢打赌,这一行代码:
p1.Equals(p4)

 is actually calling upon the Equals method of `Object` rather than yours.
尝试让您的接口实现IEqualityComparer并使显式
Equals
脱离接口定义。     
如果你想让
Contains
方法使用
IEquatable.Equals
方法,你的
BasePage
类型需要实现
IEquatable<BasePage>
而不是
IEquatable<IBaseTemplate>
。   此方法通过确定相等性   使用默认的相等比较器,   由对象定义   实施   
IEquatable<T>.Equals
方法
T
  (列表中的值的类型)。 因为你的类没有实现
IEquatable<BasePage>
,所以
Contains
方法又回归到使用虚拟的非泛型
object.Equals
方法。在你的
BasePage
类中覆盖那个方法应该可以解决问题     
对List.Contains(T item)的调用通过使用默认的相等比较器来确定相等性,由对象的T的IEquatable.Equals方法的实现(列表中的值的类型)定义。 因此,要在列表中定位的项需要提供IEquatable的实现,并且还需要覆盖Equals(Object obj)方法以调用equatable逻辑。 例如,假设您有一个这样的界面:
public interface IRole : INotifyPropertyChanged, INotifyPropertyChanging
{
    #region ConcurrencyToken
    /// <summary>
    /// Gets the unique binary concurrency token for the security role.
    /// </summary>
    /// <value>
    /// A <see cref="IList{Byte}"/> collection that contains the unique binary concurrency token for the security role.
    /// </value>
    IList<byte> ConcurrencyToken
    {
        get;
    }
    #endregion

    #region Description
    /// <summary>
    /// Gets or sets the description of the security role.
    /// </summary>
    /// <value>
    /// The human readable description of the security role.
    /// </value>
    string Description
    {
        get;
        set;
    }
    #endregion

    #region Id
    /// <summary>
    /// Gets or sets the unique identifier for the security role.
    /// </summary>
    /// <value>
    /// A <see cref="Int32"/> value that represents the unique identifier for the security role.
    /// </value>
    int Id
    {
        get;
        set;
    }
    #endregion

    #region LastModifiedBy
    /// <summary>
    /// Gets or sets the name of the user or process that last modified the security role.
    /// </summary>
    /// <value>
    /// The name of the user or process that last modified the security role.
    /// </value>
    string LastModifiedBy
    {
        get;
        set;
    }
    #endregion

    #region LastModifiedOn
    /// <summary>
    /// Gets or sets the date and time at which the security role was last modified.
    /// </summary>
    /// <value>
    /// A <see cref="Nullable{DateTime}"/> that represents the date and time at which the security role was last modified.
    /// </value>
    DateTime? LastModifiedOn
    {
        get;
        set;
    }
    #endregion

    #region Name
    /// <summary>
    /// Gets or sets the name of the security role.
    /// </summary>
    /// <value>
    /// The human readable name of the security role.
    /// </value>
    string Name
    {
        get;
        set;
    }
    #endregion
}
这个接口的默认实现可能是这个,并注意IEquatable是如何实现的:
public class Role : EntityBase, IRole, IEquatable<Role>
{
    //=======================================================================================================
    //  Constructors
    //=======================================================================================================
    #region Role()
    /// <summary>
    /// Initializes a new instance of <see cref="Role"/> class.
    /// </summary>
    public Role()
    {
    }
    #endregion

    #region Role(IEnumerable<byte> concurrencyToken)
    /// <summary>
    /// Initializes a new instance of <see cref="Role"/> class 
    /// using the specified unique binary concurrency token.
    /// </summary>
    /// <param name="concurrencyToken">The unique binary concurrency token for the security role.</param>
    /// <exception cref="ArgumentNullException">The <paramref name="concurrencyToken"/> is a <see langword="null"/> reference (Nothing in Visual Basic).</exception>
    public Role(IEnumerable<byte> concurrencyToken) : base(concurrencyToken)
    {

    }
    #endregion

    //=======================================================================================================
    //  Public Methods
    //=======================================================================================================
    #region ToString()
    /// <summary>
    /// Returns a <see cref="String"/> that represents the current <see cref="Role"/>.
    /// </summary>
    /// <returns>
    /// A <see cref="String"/> that represents the current <see cref="Role"/>.
    /// </returns>
    public override string ToString()
    {
        return this.Name;
    }
    #endregion

    //=======================================================================================================
    //  IEquatable<Role> Implementation
    //=======================================================================================================
    #region Equals(Role other)
    /// <summary>
    /// Indicates whether the current object is equal to another object of the same type.
    /// </summary>
    /// <param name="other">An object to compare with this object.</param>
    /// <returns><see langword="true"/> if the current object is equal to the other parameter; otherwise, <see langword="false"/>.</returns>
    public bool Equals(Role other)
    {
        if (other == null)
        {
            return false;
        }

        if (!String.Equals(this.Description, other.Description, StringComparison.Ordinal))
        {
            return false;
        }
        else if (!Int32.Equals(this.Id, other.Id))
        {
            return false;
        }
        else if (!String.Equals(this.Name, other.Name, StringComparison.Ordinal))
        {
            return false;
        }

        return true;
    }
    #endregion

    #region Equals(object obj)
    /// <summary>
    /// Determines whether the specified <see cref="Object"/> is equal to the current <see cref="Object"/>.
    /// </summary>
    /// <param name="obj">The <see cref="Object"/> to compare with the current <see cref="Object"/>.</param>
    /// <returns>
    /// <see langword="true"/> if the specified <see cref="Object"/> is equal to the current <see cref="Object"/>; otherwise, <see langword="false"/>.
    /// </returns>
    public override bool Equals(object obj)
    {
        return this.Equals(obj as Role);
    }
    #endregion

    #region GetHashCode()
    /// <summary>
    /// Returns the hash code for this instance.
    /// </summary>
    /// <returns>A 32-bit signed integer hash code.</returns>
    /// <a href="http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx"/>
    public override int GetHashCode()
    {
        int descriptionHashCode     = this.Description.GetHashCode();
        int idHashCode              = this.Id.GetHashCode();
        int nameHashCode            = this.Name.GetHashCode();

        /*
            * The 23 and 37 are arbitrary numbers which are co-prime.
            * 
            * The benefit of the below over the XOR (^) method is that if you have a type 
            * which has two values which are frequently the same, XORing those values 
            * will always give the same result (0) whereas the above will 
            * differentiate between them unless you're very unlucky.
        */
        int hashCode    = 23;
        hashCode        = hashCode * 37 + descriptionHashCode;
        hashCode        = hashCode * 37 + idHashCode;
        hashCode        = hashCode * 37 + nameHashCode;

        return hashCode;
    }
    #endregion

    //=======================================================================================================
    //  IRole Implementation
    //=======================================================================================================
    #region Description
    /// <summary>
    /// Gets or sets the description of this security role.
    /// </summary>
    /// <value>
    /// The human readable description of this security role. The default value is an <see cref="String.Empty"/> string.
    /// </value>
    [DataMember()]
    public string Description
    {
        get
        {
            return _roleDescription;
        }

        set
        {
            if (PropertyChangeNotifier.AreNotEqual(_roleDescription, value))
            {
                using (new PropertyChangeNotifier(OnPropertyChanging, OnPropertyChanged))
                {
                    _roleDescription = !String.IsNullOrEmpty(value) ? value : String.Empty;
                }
            }
        }
    }
    private string _roleDescription = String.Empty;
    #endregion

    #region Id
    /// <summary>
    /// Gets or sets the unique identifier for this security role.
    /// </summary>
    /// <value>
    /// A <see cref="Int32"/> value that represents the unique identifier for this security role. 
    /// The default value is <i>zero</i>.
    /// </value>
    [DataMember()]
    public int Id
    {
        get
        {
            return _roleId;
        }

        set
        {
            if (PropertyChangeNotifier.AreNotEqual(_roleId, value))
            {
                using (new PropertyChangeNotifier(OnPropertyChanging, OnPropertyChanged))
                {
                    _roleId = value;
                }
            }
        }
    }
    private int _roleId;
    #endregion

    #region Name
    /// <summary>
    /// Gets or sets the name of this security role.
    /// </summary>
    /// <value>
    /// The human readable name of this security role. The default value is an <see cref="String.Empty"/> string.
    /// </value>
    [DataMember()]
    public string Name
    {
        get
        {
            return _roleName;
        }

        set
        {
            if (PropertyChangeNotifier.AreNotEqual(_roleName, value))
            {
                using (new PropertyChangeNotifier(OnPropertyChanging, OnPropertyChanged))
                {
                    _roleName = !String.IsNullOrEmpty(value) ? value : String.Empty;
                }
            }
        }
    }
    private string _roleName = String.Empty;
    #endregion
}
    
您需要实际将p4实例添加到集合中。
coll.Add(p4);
编辑 为什么不比较GUID?
coll.Add(p1.GUID);
coll.Add(p2.GUID);
coll.Add(p3.GUID);
coll.Contains(p4.GUID);   //expect this to be true
    

要回复问题请先登录注册