none
重载Equals和GetHashCode的问题 RRS feed

  • 问题

  • public class Test
       
    {
           
    public Test() { } public int Id { get; set; }

           
    public string TName { get; set; }

           
    public TestSeries TSeries { get; set; }

           
    public TestType TType { get; set; }

           
    public bool IsComplete { get; set; }

           
    public string Remark { get; set; }

           
    public override bool Equals(object obj)
           
    {
               
    if (this == obj) return true; if (obj == null || this.GetType() != obj.GetType())
               
    {
                   
    return false;
               
    }

               
    Test hb = (Test)obj;

               
    if (this.TSeries == null)
               
    {
                   
    if (hb.TSeries != null)
                   
    {
                       
    return false;
                   
    }
               
    }
               
    else
               
    {
                   
    if (!this.TSeries.Equals(hb.TSeries))
                   
    {
                       
    return false;
                   
    }
               
    }

               
    if (this.TType == null)
               
    {
                   
    if (hb.TType != null)
                   
    {
                       
    return false;
                   
    }
               
    }
               
    else
               
    {
                   
    if (!this.TType.Equals(hb.TType))
                   
    {
                       
    return false;
                   
    }
               
    }

               
    return ((this.Id == hb.Id) && (this.TName == hb.TName)
                                         
    && (this.Remark == hb.Remark)
                                         
    && (this.IsComplete == hb.IsComplete)
                                         
    );
           
    }

           
    public override int GetHashCode()
           
    {
               
    int HashCodeId = this.Id;
               
    int HashCodeTName = this.TName == null ? 0 : this.TName.GetHashCode();
               
    int HashCodeTSeries = this.TSeries == null ? 0 : this.TSeries.GetHashCode();
               
    int HashCodeTType = this.TType == null ? 0 : this.TType.GetHashCode();
               
    int HashCodeRemark = this.Remark == null ? 0 : this.Remark.GetHashCode();
               
    int HashCodeIsComplete = this.IsComplete.GetHashCode();

               
    return HashCodeId ^ HashCodeTName ^ HashCodeTSeries ^ HashCodeTType ^ HashCodeRemark ^ HashCodeIsComplete;
           
    }
       

    请问这个类重载Equals和GetHashCode的问题出在那儿?
    2013年1月31日 7:34

答案

全部回复

  • Hi 百里无二,

      欢迎来到MSDN中文论坛。

      强烈建议你看一下Guidelines for Overloading Equals() and Operator == (C# Programming Guide).其中如果要重载GetHashCode和Equals这两个方法的话,需要继承自System.Object。 就像MFC的基类要继承CWnd一样。GetHashCode和Equals已经存在于基类中,但是你这个类必须制定这个基类。

     


    Jason Wang [MSFT]
    MSDN Community Support | Feedback to us

    2013年2月1日 4:51
    版主
  • 这本身没有错误。

    Equals符合了所有应有的特性,GetHashCode也保证相同对象返回相同的值。

    我认为在你的例子中出现错误是因为你改变了对象。

    2013年2月2日 15:59
  • 这本身没有错误。

    Equals符合了所有应有的特性,GetHashCode也保证相同对象返回相同的值。

    我认为在你的例子中出现错误是因为你改变了对象。


    那为什么不重载GetHashCode就不会出现异常呢?
    2013年2月2日 16:03
  • 楼主,你哪个地方出问题了?

    可以告诉我们你何出引用了这些重写代码?类比较还是?


    帮助一起改进论坛质量?提交你的意见于此。
    我的博客园
    慈善点击,点击此处
    和谐拯救危机,全集下载,净化人心

    2013年2月3日 2:30
    版主
  • public class Test
        {
            public Test() { }
    
            public int Id { get; set; }
    
            public string TName { get; set; }
    
            public bool IsComplete { get; set; }
    
            public string Remark { get; set; }
    
            public override bool Equals(object obj)
            {
                if (this == obj) return true;
    
                if (obj == null || this.GetType() != obj.GetType())
                {
                    return false;
                }
    
                Test t = (Test)obj;
    
                return ((this.Id == t.Id) && (this.TName == t.TName)
                                         && (this.Remark == t.Remark)
                                         && (this.IsComplete == t.IsComplete)
                                         );
            }
    
            public override int GetHashCode()
            {
                int HashCodeId = this.Id;
                int HashCodeTName = this.TName == null ? 0 : this.TName.GetHashCode();
                int HashCodeRemark = this.Remark == null ? 0 : this.Remark.GetHashCode();
                int HashCodeIsComplete = this.IsComplete.GetHashCode();
    
                return HashCodeId ^ HashCodeTName ^ HashCodeRemark ^ HashCodeIsComplete;
            }
        }
    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Button Content="获取数据1" Height="23" HorizontalAlignment="Left" Margin="12,38,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
            <Button Content="获取数据2" Height="23" HorizontalAlignment="Left" Margin="12,82,0,0" Name="button2" VerticalAlignment="Top" Width="75" Click="button2_Click" />
            <ListBox Name="lstTestData"  Height="177" HorizontalAlignment="Left" Margin="127,38,0,0" VerticalAlignment="Top" Width="120" 
                     DisplayMemberPath="TName"/>
            <GroupBox Header="详细信息"  Height="176" HorizontalAlignment="Left" Margin="288,39,0,0" Name="groupBox1" VerticalAlignment="Top" Width="200">
                <Grid Name="gridDetailed"  DataContext="{Binding SelectedItem, ElementName=lstTestData,Mode=OneWay}">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="67*" />
                        <ColumnDefinition Width="121*" />
                    </Grid.ColumnDefinitions>
                    <TextBox Height="23" Text="{Binding Path=TName}"  HorizontalAlignment="Left" Margin="21,19,0,0" Name="textBox1" VerticalAlignment="Top" Width="87" Grid.Column="1" />
                    <Label Content="TName:" Height="28" HorizontalAlignment="Left" Margin="21,15,0,0" Name="label1" VerticalAlignment="Top" Grid.ColumnSpan="2" />
                    <CheckBox Name="cbIsComplete"  Content="是否完成" IsChecked="{Binding Path=IsComplete}"  Height="16" HorizontalAlignment="Left" Margin="21,66,0,0" VerticalAlignment="Top" Grid.Column="1" />
                    <Button Content="更新" Height="23" HorizontalAlignment="Left" Margin="24,121,0,0" Name="button3" VerticalAlignment="Top" Width="75" Click="button3_Click" Grid.Column="1" />
                </Grid>
            </GroupBox>
        </Grid>
    </Window>
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Collections.ObjectModel;
    
    namespace WpfApplication1
    {
        /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                ObservableCollection<Test> data = new ObservableCollection<Test>();
                for (int i = 0; i < 6; i++)
                {
                    Test t = new Test()
                    {
                        Id = i,
                        IsComplete = false,
                        TName = i.ToString(),
                    };
                    data.Add(t);
                }
                lstTestData.ItemsSource = data;
            }
    
            private void button2_Click(object sender, RoutedEventArgs e)
            {
                ObservableCollection<Test> data = new ObservableCollection<Test>();
                for (int i = 0; i < 8; i++)
                {
                    Test t = new Test()
                    {
                        Id = 10 + i,
                        IsComplete = true,
                        TName = (10 + i).ToString(),
                    };
                    data.Add(t);
                }
                lstTestData.ItemsSource = data;
            }
    
            private void button3_Click(object sender, RoutedEventArgs e)
            {
                Test test = gridDetailed.DataContext as Test;
                if (test!=null)
                {
                    test.IsComplete = cbIsComplete.IsChecked.HasValue ? cbIsComplete.IsChecked.Value : false;
                }
            }
        }
    }

    1,点击获取数据。(这是listbox出现了构造的数据项)
    2,listbox中选择一项。(这时对应的详细信息框中相应的信息出现)
    3,修改“是否完成”,原本是没有选择,现在选择,然后点击“更新”
    4,再回到list选择其他任一项
    5,再次选择修改项
    6,再次选择其他任何一项,这时就会出现异常

    在Test类中不重载GetHashCode就不会出现这个问题了,我很纠结这是为什么?

    还有就是重载GetHashCode有没有什么比较好的参考?

    2013年2月3日 3:42
  • 问题应该是出在修改列表项里面对象的数据这里

    test.IsComplete = cbIsComplete.IsChecked.HasValue ? cbIsComplete

    异常不是这句抛出的,是内部异常,不太懂,你有时间可以帮我调试一下

    2013年2月3日 5:44
  • hi,

    基本上,没事的话不需要override,除非你有特别需求

    个人最常用的方式是比较两物件里的栏位是否都相同,看你提供的例子,也是想要这样做

    http://www.dotblogs.com.tw/yc421206/archive/2012/12/17/85732.aspx

    GetHashCode 是用来返回唯一值,会出错可能是集合里面的值有重复。

    或许你也可以参考以下的写法
    http://www.dotblogs.com.tw/yc421206/archive/2013/01/05/86781.aspx
    http://component.codeplex.com/SourceControl/changeset/view/28740#661301


    秘訣無它,唯勤而已 http://www.dotblogs.com.tw/yc421206/

    2013年2月4日 6:45
  • 百里无二,

    现在我怀疑你的Equals代码会不会抛出异常?
    因为你传入的参数是object,而且内部使用了强制转换:
    Test hb = (Test)obj;
    这是不安全的,建议:

    Test tst = obj as Test;
    if(tst!=null)
    {
      …………
    }
    return false;

    帮助一起改进论坛质量?提交你的意见于此。
    我的博客园
    慈善点击,点击此处
    和谐拯救危机,全集下载,净化人心

    2013年2月4日 7:20
    版主