RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 630012
Accepted
Eladei
Eladei
Asked:2020-02-20 02:13:06 +0000 UTC2020-02-20 02:13:06 +0000 UTC 2020-02-20 02:13:06 +0000 UTC

将可观察类对象的修改后的属性传递给订阅者

  • 772

今天是个好日子!

出现了以下问题:

有一个类。例如 Book Book,其中定义了一组属性。

public class Book {
    string Name {get; set;}
    string Author {get; set;}
    double price {get; set;}

    // Далее определено Событие на изменение свойств книги OnBookPropertiesChanged
}

假设某个类的另一个对象订阅了Book类对象的OnBookPropertiesChanged事件。如何将 Book 类对象的某些属性的更改值传递给该对象?

同时,我想知道:有没有办法避免创建单独的事件来更改 Book 类对象的每个单独属性?事实上,Book 可以有很多属性。(据了解,它们在程序中以单独的形式输入,用于后续存储在类对象中)。

有一个选项可以做到这一点:

public interface IBook {
    string Name { get; }
    string Author { get; }
    double Price { get; }
}

public class Book : IBook {
    public string Name { get; private set; }
    public string Author { get; private set; }
    public double Price { get; private set; }

    public Book(string name, string author, double price) {
        Name = name;
        Author = author;
        Price = price;
    }

    public void UpdateBookProperties(IBook newBookProperties) {
        this.Name = newBookProperties.Name;
        this.Author = newBookProperties.Author;
        this.Price = newBookProperties.Price;

        OnBookPropertiesChanged();
    }

    public event Action<IBook> BookPropertiesChanged;

    private void OnBookPropertiesChanged() {
        if(BookPropertiesChanged != null) {
            IBook newBookProperties = 
                BookFactory.CreateBook(this.Name, this.Author, this.Price);

            BookPropertiesChanged(newBookProperties);
        }
    }
}

public class BookFactory {
    public static IBook CreateBook(string name, string author, double price) {
        return new Book(name, author, price);
    }
}

但我不喜欢这个选项。有几个原因:

1) 要更改 Book 类当前对象的任何属性,您必须创建一个新对象,在该对象中将指定新属性。

2) 因此,不可能对一本书的单个属性进行简单的更改。否则,订阅 BookPropertiesChanged 事件的对象根本看不到图书属性的更改。

您能告诉我在没有冗余代码的情况下实现这种情况的最佳方法吗?

c#
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Best Answer
    Dmitry
    2020-02-21T02:43:49Z2020-02-21T02:43:49Z

    您可以从属性设置器发送消息

    类型

    命名空间 mvvm

    {

    public abstract class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            PropertyChanged?.Invoke(sender, e);
        }
    
        public void RaisePropertyChanged<T>(object sender, Expression<Func<T>> propertyExpresssion)
        {
            var propertyName = PropertySupport.ExtractPropertyName(propertyExpresssion);
            OnPropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
        }
    }
    
    public static class PropertySupport
    {
        public static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpresssion)
        {
            if (propertyExpresssion == null)
            {
                throw new ArgumentNullException("propertyExpresssion");
            }
    
            var memberExpression = propertyExpresssion.Body as MemberExpression;
            if (memberExpression == null)
            {
                throw new ArgumentException("The expression is not a member access expression.", "propertyExpresssion");
            }
    
            var property = memberExpression.Member as PropertyInfo;
            if (property == null)
            {
                throw new ArgumentException("The member access expression does not access a property.", "propertyExpresssion");
            }
    
            var getMethod = property.GetGetMethod(true);
            if (getMethod.IsStatic)
            {
                throw new ArgumentException("The referenced property is a static property.", "propertyExpresssion");
            }
    
            return memberExpression.Member.Name;
        }
    }
    
    public class Book : ObservableObject
    {
        private string _name;
        private string _author;
        private double _price;
    
        public string Name
        {
            get { return _name; }
            set
            {
                if (!_name.Equals(value, StringComparison.OrdinalIgnoreCase))
                {
                    _name = value;
                    RaisePropertyChanged(this, () => Name);
                }
            }
        }
    
        public string Author
        {
            get { return _author; }
            set
            {
                if (!_author.Equals(value, StringComparison.OrdinalIgnoreCase))
                {
                    _author = value;
                    RaisePropertyChanged(this, () => Author);
                }
            }
        }
    
        public double Price
        {
            get { return _price; }
            set
            {
                if (_price != value)
                {
                    _price = value;
                    RaisePropertyChanged(this, () => Price);
                }
            }
        }
    }
    
    class BookUser
    {
        public void ObserveBook(Book book)
        {
            book.PropertyChanged += Book_PropertyChanged;
        }
    
        private void Book_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            var book = sender as Book;
            if (book != null)
            {
                if (e.PropertyName == PropertySupport.ExtractPropertyName(() => book.Author))
                {
                    Console.WriteLine("Author is changed");
                }
                if (e.PropertyName == PropertySupport.ExtractPropertyName(() => book.Name))
                {
                    Console.WriteLine("Name is changed");
                }
                if (e.PropertyName == PropertySupport.ExtractPropertyName(() => book.Price))
                {
                    Console.WriteLine("Price is changed");
                }
            }
        }
    }
    
    • 2
  2. Eladei
    2020-02-21T14:23:30Z2020-02-21T14:23:30Z

    谢谢大家的代码和提示。

    结果,我确定了以下实现:

    // Описывает передаваемое свойство, 
    // значение которого было изменено в соответствующем классе
    public interface ITransferredArgs {
        // Название измененного свойства
        string PropertyName { get; }
    
        // Новое значение, присвоенное свойству
        object PropertyValue { get; }
    }
    
    public interface IBook {
        string FirstName { get; set; }
        string Author { get; set; }
        double Price { get; set; }
    
        event Action<ITransferredArgs> BookPropertiesChanged;
    }
    
    public class BookArgs : ITransferredArgs {
        public string PropertyName { get; set; }
        public object PropertyValue { get; set; }
    
        public BookArgs( string propertieName, object propertieValue ) {
            this.PropertyName = propertieName;
            this.PropertyValue = propertieValue;
        }
    }
    
    public class Book : IBook {
        string name;
        string author;
        double price;
    
        public string FirstName {
            get {
                return name;
            }
            set {
                if(name != value) {
                    name = value;
                    OnBookPropertiesChanged(GetPropertyCallerName(), value);
                }
            }
        }
        public string Author {
            get {
                return author;
            }
            set {
                if(author != value) {
                    author = value;
                    OnBookPropertiesChanged(GetPropertyCallerName(), value);
                }
            }
        }
        public double Price {
            get {
                return price;
            }
            set {
                if(price != value) {
                    price = value;
                    OnBookPropertiesChanged(GetPropertyCallerName(), value);
                }
            }
        }
    
        public Book(string name) {
            FirstName = name;
        }
    
        ~Book() {
            BookPropertiesChanged = null;
        }
    
        string GetPropertyCallerName([CallerMemberName] string propertyName = "") {
            return propertyName;
        }
    
        public void UpdateBookProperties(IBook newBookProperties) {
            this.FirstName = newBookProperties.FirstName;
            this.Author = newBookProperties.Author;
            this.Price = newBookProperties.Price;
        }
    
        public event Action<ITransferredArgs> BookPropertiesChanged;
    
        private void OnBookPropertiesChanged(string propertieName, object propertieValue) {
            if(BookPropertiesChanged != null) {
                ITransferredArgs newBookProperties = 
                    BookFactory.CreateBookArgs( propertieName, propertieValue );
    
                BookPropertiesChanged(newBookProperties);
            }
        }
    }
    
    public class BookFactory {
        public static IBook CreateBook(string name) {
            return new Book(name);
        }
    
        public static IBook CreateBook(IBook book) {
            Book newBook = new Book(book.Author);
            newBook.FirstName = book.FirstName;
            newBook.Price = book.Price;
            return newBook;
        }
    
        public static ITransferredArgs CreateBookArgs(string propertieName, object propertieValue) {
            return new BookArgs(propertieName, propertieValue);
        }
    }
    
    public class Visiter {
        // Наблюдаемая книга
        public IBook observableBook;
    
        public Visiter(IBook book) {
            // Подписываемся на событие изменения наблюдаемой книги
            book.BookPropertiesChanged += OnBookDataChanged;
    
            // Копируем данные (не ссылку) в объект observableBook.
            observableBook = BookFactory.CreateBook(book);
        }
    
        // Обновляем параметры наблюдаемой книги
        public void OnBookDataChanged(ITransferredArgs args) {
            // Получаем название изменяемого свойства
            PropertyInfo propertyInfo = observableBook.GetType().GetProperty(args.PropertyName);
    
            // Обновляем соответствующее свойство в observableBook
            propertyInfo.SetValue(observableBook, args.PropertyValue);
            /*
            // Альтернативный вариант, требующий изменения названия поля
            // в case при изменении названия соответствующего поля в наблюдаемом классе
            switch(args.PropertyName) {
                case ("FirstName"):
                    observableBook.FirstName = (string)args.PropertyValue;
                    break;
                case ("Author"):
                    observableBook.Author = (string)args.PropertyValue;
                    break;
                case ("Price"):
                    observableBook.Price = (double)args.PropertyValue;
                    break;
            }*/
        }
    
        // Вывести информацию о наблюдаемой книге
        public void ShowObservableBook() {
            Console.WriteLine("Имя наблюдаемой книги = " + observableBook.FirstName);
            Console.WriteLine("Автор наблюдаемой книги = " + observableBook.Author);
            Console.WriteLine("Цена наблюдаемой книги = " + observableBook.Price + "\n");
        }
    }
    
    • 2

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    Python 3.6 - 安装 MySQL (Windows)

    • 1 个回答
  • Marko Smith

    C++ 编写程序“计算单个岛屿”。填充一个二维数组 12x12 0 和 1

    • 2 个回答
  • Marko Smith

    返回指针的函数

    • 1 个回答
  • Marko Smith

    我使用 django 管理面板添加图像,但它没有显示

    • 1 个回答
  • Marko Smith

    这些条目是什么意思,它们的完整等效项是什么样的

    • 2 个回答
  • Marko Smith

    浏览器仍然缓存文件数据

    • 1 个回答
  • Marko Smith

    在 Excel VBA 中激活工作表的问题

    • 3 个回答
  • Marko Smith

    为什么内置类型中包含复数而小数不包含?

    • 2 个回答
  • Marko Smith

    获得唯一途径

    • 3 个回答
  • Marko Smith

    告诉我一个像幻灯片一样创建滚动的库

    • 1 个回答
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Алексей Шиманский 如何以及通过什么方式来查找 Javascript 代码中的错误? 2020-08-03 00:21:37 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5