【问题标题】:How can I disambiguate this call to a generic method?如何消除对泛型方法的调用的歧义?
【发布时间】:2013-01-31 08:31:39
【问题描述】:

鉴于以下简单的控制台应用程序,它说明了通知更改属性的两种方式:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var person = new Person(){ Name = "Me" };
            person.Age = 20;
            person.Weight = 80.5F;
                    person.RandomProperty = new RandomComplexObject();

            Console.ReadKey();
        }
    }


    public class Person : BaseObject
    {
        public string Name
        {
            get { return _name; }
            set { SetProperty(ref value, ref _name, false); }
        }

        public int Age
        {
            get { return _age; }
            set { SetProperty<int>(ref value, ref _age, true, "Age", "Weight"); }
        }

        public float Weight
        {
            get { return _weight; }
            set { SetProperty(ref value, ref _weight, true, () => Weight, () => Age); }
        }

        public RandomComplexObject RandomProperty
        {
            get { return _rco; }

            //*** the following line has the error:
            //-------------------------------------
            set { SetProperty(ref value, ref _rco, true, () => Name, () => Age, () => Weight); } 
        }

        private float _weight;
        private int _age;
        private string _name;
        private RandomComplexObject _rco;
    }

    public class BaseObject : INotifyPropertyChanged
    {

        protected void OnPropertyChanged<T>(Expression<Func<T>> propertyExpression)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                var body = propertyExpression.Body as MemberExpression;
                var expression = body.Expression as ConstantExpression;
                handler(expression.Value, new PropertyChangedEventArgs(body.Member.Name));
            }
        }

        private void OnPropertyChanged(string propertyName)              
        {
            var handler = PropertyChanged;
            if (handler == null)
                return;
            handler(this, new PropertyChangedEventArgs(propertyName));
        }

        protected bool SetProperty<T>(ref T newValue, ref T currentValue, bool notify, params string[] notifications)
        {
            if (EqualityComparer<T>.Default.Equals(newValue, currentValue))
                return false;

            currentValue = newValue;
            if (notify)
                foreach (var propertyName in notifications)
                    OnPropertyChanged(propertyName);

            return true;
        }

        protected bool SetProperty<T, TProperty>(ref T newValue, ref T currentValue, bool notify, params Expression<Func<TProperty>>[] notifications)
        {
            if (EqualityComparer<T>.Default.Equals(newValue, currentValue))
                return false;

            currentValue = newValue;
            if (notify)
                foreach (var notification in notifications)
                    OnPropertyChanged(notification);

            return true;
        }

        public event PropertyChangedEventHandler PropertyChanged;

    }

    public class RandomComplexObject{}
}

在方法调用SetProperty(ref value, ref _rco, true, () =&gt; Name, () =&gt; Age, () =&gt; Weight);就行了我遇到编译错误:

无法将 lambda 表达式转换为类型“字符串”,因为它不是委托类型

IDE中直接显示的错误是:

无法从用法中推断方法“bool ConsoleApplication1.BaseObject.SetProperty(ref T, ref T, bool, params Expression>[])”的类型参数。尝试明确指定类型参数。

如何消除对SetProperty() 方法的调用的歧义?有没有更简洁的语法写法?

【问题讨论】:

  • 你到底想用这个设计完成什么?
  • @RoyDictus 这是为了提供一个选项,开发人员可以避免在属性通知中使用魔术字符串。在 SetProperty() 调用中传递单个 lambda 是微不足道的,但我希望选择通知多个属性。不幸的是,删除采用params string[]SetProperty() 将涉及合理数量的更改 - 我宁愿调用代码随着文件的接触而逐步更改。
  • 在属性的设置器中,您指的是多个不相关的属性。这是一个糟糕的设计。如果您想要属性更改通知,在字符串中硬编码属性名称并不是那么糟糕——它不是 100% 干净的,但至少它比上面代码中的方法干净得多。我会坚持使用通知属性更改的标准方式msdn.microsoft.com/en-us/library/ms743695.aspx。万事如意!

标签: c# generics inotifypropertychanged disambiguation


【解决方案1】:

以下变体至少可以编译。

public RandomComplexObject RandomProperty
{
    get { return _rco; }

    set
    {
        SetProperty(
            ref value,
            ref _rco,
            true,
            () => Name,
            () => Age.ToString(),    //instead of () => Age
            () => Weight.ToString());//instead of () => Weight
    }
}

我猜,您收到的错误首先是基于编译器无法推断出TProperty 的事实

protected bool SetProperty<T, TProperty>(
    ref T newValue, 
    ref T currentValue, 
    bool notify, 
    params Expression<Func<TProperty>>[] notifications)
{
    //...
}

因为它需要可变数量的 Expression&lt;Func&lt;TProperty&gt;&gt; 类型的参数,并且您传递了 lambda,返回 stringintfloat。绝对编译器无法确定,其中哪一个是TProperty

Weight 属性的设置器中:

public float Weight
{
    get { return _weight; }
    set
    {
        SetProperty(ref value, ref _weight, true, () => Weight, () => Age);
    }
}

具有float 类型的Weightint 类型的Age,编译器推断TPropertyfloat,因为存在从intfloat 的隐式转换。

【讨论】:

  • 谢谢,在Expression&lt;Func&lt;TProperty&gt;&gt;[] 中键入强制是问题所在。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-29
  • 1970-01-01
  • 1970-01-01
  • 2013-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多