如何在c#中检测属性值(ReferenceType属性)是否已更改?

如何在c#中检测属性值(ReferenceType属性)是否已更改?,c#,asp.net-mvc,reference-type,C#,Asp.net Mvc,Reference Type,我有一个Customer类,我希望在用户更改Customer.CityInfo属性的值时收到通知 public class City { public long Id {get;set;} public string Code {get;set;} } public class Customer { private City cityInfo; private string name; public long Id { get; set; }

我有一个
Customer
类,我希望在用户更改
Customer.CityInfo
属性的值时收到通知

public class City
{
    public long Id {get;set;}
    public string Code {get;set;}
}

public class Customer
{

    private City cityInfo;
    private string name;

    public long Id { get; set; }
    public bool IsCityModified { get; set;}
    public bool IsCustomerNameModified { get; set; }

    public string Name 
    { 
        get{ return name;} 
        set
        {
           if(name!=value)
           {
              IsCustomerNameModified=true; }name=value;
           } 
        }
     }


    public City CityInfo 
    {
    get
        {
           if(cityInfo==null)
           {
              cityInfo=new City();
           }
           return cityInfo;
         }

      set{
          if(this.cityInfo!=value)
          {
             IsCityModified =true;
          }
          this.cityInfo=value;
       }   
  }
}

public ActionResult Save()
{
    Customer customer=this.currentCustomerSession;
    if(TryUpdateModel<Customer>(customer)){
       UpdateModel<Customer>(customer)
    }
    if(customer.IsCustomerNameModified ){
        //I am able to detect whether the customerName value has been changed in the frontend.
    }
    if(customer.IsCityModified){
        //I am not able to detect whether the city value has been changed in the frontend.
    }
}
公共级城市
{
公共长Id{get;set;}
公共字符串代码{get;set;}
}
公共类客户
{
私人城市信息;
私有字符串名称;
公共长Id{get;set;}
公共bool已修改{get;set;}
public bool IsCustomerNameModified{get;set;}
公共字符串名
{ 
获取{返回名称;}
设置
{
如果(名称!=值)
{
IsCustomerNameModified=true;}name=value;
} 
}
}
公共城市信息
{
得到
{
if(cityInfo==null)
{
cityInfo=新城();
}
返回城市信息;
}
设置{
if(this.cityInfo!=值)
{
IsCityModified=true;
}
此.cityInfo=值;
}   
}
}
公共操作结果保存()
{
客户=this.currentCustomerSession;
if(TryUpdateModel(客户)){
UpdateModel(客户)
}
如果(customer.iscustomername已修改){
//我能够检测前端中的customerName值是否已更改。
}
if(customer.IsCityModified){
//我无法检测前端的城市值是否已更改。
}
}
如果客户名称因其值类型而更改,我可以将标志(IsCustomerNameModified)设置为true。但无法检测引用类型中所做的更改


有人能帮忙吗?

这种问题通常通过变更通知系统处理。见本文:

片段:

  public string PersonName
  {
      get { return name; }
      set
      {
          name = value;
          // Call OnPropertyChanged whenever the property is updated
          OnPropertyChanged("PersonName");
      }
  }

  // Create the OnPropertyChanged method to raise the event 
  protected void OnPropertyChanged(string name)
  {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (handler != null)
      {
          handler(this, new PropertyChangedEventArgs(name));
      }
  }

使用此模式将帮助您避免设置标志或其他此类阴谋

既然我正确理解了这个问题,我建议执行以下操作:

City
对象中添加
public bool Changed{get;private set;}
属性

然后在对象的每个属性中,检查值是否已更改,如果已更改,则将
已更改
标志设置为true:

public int Id
{
   { get { return this.id } }
   {
      set
      {
         if (this.id != value) Changed = true;
         this.id = value;
      }
   }
}
它类似于实现
IPropertyChanged
接口,但通过这种方式,您可以确保只需检查对象是否修改过一次


对象的引用似乎没有更改,因此您只需检查它的
已更改
属性(如果对象的引用真的更改了,我以前的答案会有效)

Paul是正确的,您需要实现INotifyProperty更改。下面是一个简单的例子。这很简单

  public class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private int _number;

        public BaseViewModel()
        {
            PropertyChanged += (o, p) =>
                                   {
                                       //this is the place you would do what you wanted to do
                                       //when the property has changed.
                                   };
        }

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) 
                handler(this, new PropertyChangedEventArgs(propertyName));
        }

        public int Number
        {
            get { return _number; }
            set
            {
                _number = value;
                OnPropertyChanged("Number");
            }
        }
    }

我同意Paul的回答,但您甚至可能需要重写City类中的Equals()和GetHashCode()函数。重写函数可以检查代码和ID是否已更改

public override bool Equals( object obj )
{
    City other = obj as City;

    if ( ( other != null ) && ( other.Id == this.Id ) && ( other.Code == this.Code ) )
    {
        return ( true );
    }

    return ( false );
}

public override int GetHashCode( )
{
    return ( this.Id ^ this.Code.GetHashCode() ) ;
}

您可以使用INotifyPropertyChanged,但我猜您没有将对象绑定到某个UI元素。 在这种情况下,如果只需要知道CityInfo属性是否已更改,则最简单的 解决方案是引发自定义事件

public class Customer
{

    private City cityInfo;
    private string name;

    public long Id { get; set; }
    public bool IsCityModified { get; set;}
    public event Action<City> OnCityInfoChanged;
    public bool IsCustomerNameModified { get; set; }

    public string Name 
    { 
        get{ return name;} 
        set
        {
           if(name!=value)
           {
              IsCustomerNameModified=true; }name=value;
           } 
        }
     }


    public City CityInfo 
    {
    get
        {
           if(cityInfo==null)
           {
              cityInfo=new City();
           }
           return cityInfo;
         }

      set{
          if(this.cityInfo ==value)
                  return;
             IsCityModified =true;
             this.cityInfo=value;
             if(OnCityInfoChanged != null)
                OnCityInfoChanged(value);
       }   
  }
}
公共类客户
{
私人城市信息;
私有字符串名称;
公共长Id{get;set;}
公共bool已修改{get;set;}
公共事件行动一经改变;
public bool IsCustomerNameModified{get;set;}
公共字符串名
{ 
获取{返回名称;}
设置
{
如果(名称!=值)
{
IsCustomerNameModified=true;}name=value;
} 
}
}
公共城市信息
{
得到
{
if(cityInfo==null)
{
cityInfo=新城();
}
返回城市信息;
}
设置{
if(this.cityInfo==值)
返回;
IsCityModified=true;
此.cityInfo=值;
if(oncitynfochanged!=null)
oncitynfochanged(值);
}   
}
}

公共操作结果保存()
{
客户=this.currentCustomerSession;
customer.oncitynfochanged+=新操作((cityInfo)=>{//使用新的cityInfo做点什么});
if(TryUpdateModel(客户)){
UpdateModel(客户)
}
如果(customer.iscustomername已修改){
//我能够检测前端中的customerName值是否已更改。
}
if(customer.IsCityModified){
//我无法检测前端的城市值是否已更改。
}
}

用户如何与应用程序通信?通过win表单?字符串不是值类型,而是(不可变)引用类型。请问您为什么想知道它是否更改?在某些情况下,验证是否所有字段都已更改为执行较小的更新只需比更新所有内容花费更多的时间。但也许你还有另一个我不知道的原因:)@Fjodr我正在使用MVC表单进行更新。我尝试了上述方法,但在访问this.cityInfo.Id本身时this.cityInfo值已更改。所以(this.cityInfo.Id!=value.Id)总是false。感谢您的重播。替换了我的答案,因为我的上一个答案与您在评论中所做的精确性无关。我将您的解决方案实现为private void NotifyPropertyChanged([CallerMemberName]String propertyName=”“){PropertyChangedEventHandler=PropertyChanged;if(handler!=null){handler(这是新的PropertyChangedEventArgs(propertyName));}}但每次PropertyChanged都为null。恐怕,但是OnPropertyChanged()fires@Sravan:仔细阅读那篇链接的文章。实际上,您需要添加一个事件处理程序,这样它就会启动。如果没有人在侦听,它将不会触发(它是空的)。另外,请不要将代码粘贴到注释中。这很难读。如果您更改代码,请将其添加到您的帐户中
public ActionResult Save()
{
    Customer customer=this.currentCustomerSession;
customer.OnCityInfoChanged += new Action<CityInfo>( (cityInfo) => {//Do Something with New CityInfo});
    if(TryUpdateModel<Customer>(customer)){
       UpdateModel<Customer>(customer)
    }
    if(customer.IsCustomerNameModified ){
        //I am able to detect whether the customerName value has been changed in the frontend.
    }
    if(customer.IsCityModified){
        //I am not able to detect whether the city value has been changed in the frontend.
    }
}