Given the following simple console application which illustrates two ways of notifying on changed properties:
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{}
}
on the line with the method call SetProperty(ref value, ref _rco, true, () => Name, () => Age, () => Weight);
I am experiencing a compilation error:
Cannot convert lambda expression to type 'string' because it is not a delegate type
the error shown directly in the IDE is:
The type arguments for method 'bool ConsoleApplication1.BaseObject.SetProperty(ref T, ref T, bool, params Expression<Func<TProperty>>[])' cannot be inferred from the usage. Try specifying the type arguments explicitly.
How can I disambiguate this call to the SetProperty()
method? Is there a syntactically cleaner way to write this?
The following variant at least compiles.
public RandomComplexObject RandomProperty
{
get { return _rco; }
set
{
SetProperty(
ref value,
ref _rco,
true,
() => Name,
() => Age.ToString(), //instead of () => Age
() => Weight.ToString());//instead of () => Weight
}
}
The error you're receving, I guess, was in the first place based on the fact that compiler couldn't infer the TProperty
for
protected bool SetProperty<T, TProperty>(
ref T newValue,
ref T currentValue,
bool notify,
params Expression<Func<TProperty>>[] notifications)
{
//...
}
as it's expecting a variable number of arguments of type Expression<Func<TProperty>>
and you passed there lambdas, returning string
, int
and float
. Definitely compiler couldn't determine, which one of them was TProperty
.
In the setter of the Weight
property:
public float Weight
{
get { return _weight; }
set
{
SetProperty(ref value, ref _weight, true, () => Weight, () => Age);
}
}
having Weight
of type float
and Age
of type int
, compiler inferred TProperty
was float
, as there is an implicit conversion from int
to float
.