简体   繁体   中英

Cannot Infer type in property getter

I am working on a bindable base class that implements INotifyPropertyChanged and IDataErrorInfo so that I can write properties that bind to WPF with change notification and allow me to use DataAnnotations validation.

Kudos to this article: https://code.msdn.microsoft.com/windowsdesktop/Validation-in-MVVM-using-12dafef3 which I have copied from shamelessly

although the article is great, it doesn't take advantage of CallerMemberName so I'm trying to clean things up a bit.

One nifty thing the sample author did was to write SetValue and GetValue methods that store all private property values in a dictionary, which allows you to skip storing the property value in a private field in the class. The author used four functions to do this:

    /// <summary>
    /// Sets the value of a property.
    /// </summary>
    /// <typeparam name="T">The type of the property value.</typeparam>
    /// <param name="propertySelector">Expression tree contains the property definition.</param>
    /// <param name="value">The property value.</param>
    protected void SetValue<T>(Expression<Func<T>> propertySelector, T value)
    {
        string propertyName = GetPropertyName(propertySelector);

        SetValue<T>(propertyName, value);
    }

    /// <summary>
    /// Sets the value of a property.
    /// </summary>
    /// <typeparam name="T">The type of the property value.</typeparam>
    /// <param name="propertyName">The name of the property.</param>
    /// <param name="value">The property value.</param>
    protected void SetValue<T>(string propertyName, T value)
    {
        if (string.IsNullOrEmpty(propertyName))
        {
            throw new ArgumentException("Invalid property name", propertyName);
        }

        _values[propertyName] = value;
        NotifyPropertyChanged(propertyName);
    }

    /// <summary>
    /// Gets the value of a property.
    /// </summary>
    /// <typeparam name="T">The type of the property value.</typeparam>
    /// <param name="propertySelector">Expression tree contains the property definition.</param>
    /// <returns>The value of the property or default value if not exist.</returns>
    protected T GetValue<T>(Expression<Func<T>> propertySelector)
    {
        string propertyName = GetPropertyName(propertySelector);

        return GetValue<T>(propertyName);
    }

    /// <summary>
    /// Gets the value of a property.
    /// </summary>
    /// <typeparam name="T">The type of the property value.</typeparam>
    /// <param name="propertyName">The name of the property.</param>
    /// <returns>The value of the property or default value if not exist.</returns>
    protected T GetValue<T>(string propertyName)
    {
        if (string.IsNullOrEmpty(propertyName))
        {
            throw new ArgumentException("Invalid property name", propertyName);
        }

        object value;
        if (!_values.TryGetValue(propertyName, out value))
        {
            value = default(T);
            _values.Add(propertyName, value);
        }

        return (T)value;
    }

I have replaced these four functions with the following two:

    /// <summary>
    /// Sets the value of a property.
    /// </summary>
    /// <typeparam name="T">The type of the property value.</typeparam>
    /// <param name="propertyName">The name of the property.</param>
    /// <param name="value">The property value.</param>
    protected void SetValue<T>(T value, [CallerMemberName] string propertyName = "")
    {
        if (string.IsNullOrEmpty(propertyName))
        {
            throw new ArgumentException("Invalid property name", propertyName);
        }

        _values[propertyName] = value;
        NotifyPropertyChanged(propertyName);
    }

    /// <summary>
    /// Gets the value of a property.
    /// </summary>
    /// <typeparam name="T">The type of the property value.</typeparam>
    /// <param name="propertyName">The name of the property.</param>
    /// <returns>The value of the property or default value if not exist.</returns>
    protected T GetValue<T>([CallerMemberName] string propertyName = "")
    {
        if (string.IsNullOrEmpty(propertyName))
        {
            throw new ArgumentException("Invalid property name", propertyName);
        }

        object value;
        if (!_values.TryGetValue(propertyName, out value))
        {
            value = default(T);
            _values.Add(propertyName, value);
        }

        return (T)value;
    }

I think it's an improvement because it eliminates a few functions and simplifies calling the methods.

A property using the original functions is implemented as follows:

    [Range(1, 100, ErrorMessage = "Age should be between 1 to 100")]
    public int Age
    {
        get { return GetValue(() => Age); }
        set { SetValue(() => Age, value); }
    }

I would like to implement the same property in mine as shown below:

    [Range(1, 100, ErrorMessage = "Age should be between 1 to 100")]
    public int Age
    {
        get { return GetValue(); }
        set { SetValue(value); }
    }

The only problem is that GetValue gives me the error:

The type arguments for method ___.GetValue(string)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

So I have to implement it this way:

    [Range(1, 100, ErrorMessage = "Age should be between 1 to 100")]
    public int Age
    {
        get { return GetValue<int>(); }
        set { SetValue(value); }
    }

Any Ideas? I can't see why the original code could infer the type but my code can't.

您可以使GetValue的返回类型为dynamic ,它将被强制返回到属性类型,而不会出现错误。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM