接口传递Setter编译错误

时间:2012-10-26 18:01:10

标签: c# interface

我在名为Owner的类上有一个名为CustomerForOwner的属性。我想要一个只读版本的Owner类,所以我创建了一个名为OwnerReadOnly的包装类。我遇到的问题是我有引用类型属性。为了创建该对象的ReadOnly版本,我使用了一个接口,以便Owner和OwnerReadOnly都可以拥有一个名为CustomerForOwner(ICustomer)的属性。 OwnerReadOnly.CustomerForOwner将返回CustomerReadOnly,Owner.CustomerForOwner将返回Customer。

简化版课程:

public class Owner : ProjectBase<Owner>, IOwner
{

    private Customer _customerForOwner;
    private string _ownerName

    public virtual ICustomer CustomerForOwner
    {
        get { return _customerForOwner; }
        set 
        {
            SetField(ref _customerForOwner, value, () => CustomerForOwner);
            value.PropertyChanged += this.OnItemPropertyChanged;
        }
    }

    public virtual string OwnerName
        {
            get { return _ownerName; }
            set { SetField(ref _ownerName, value, () => OwnerName); }
        }

    public Owner(DateTime created, string createdBy)  :
            base(created, createdBy) { }
    }


    public class OwnerReadOnly : Owner
    {

        public override ICustomer CustomerForOwner
        {
            get { return (CustomerReadOnly)base.CustomerForOwner; }
        }

        public override string OwnerName
        {
            get { return base.OwnerName; }
        }

        public OwnerReadOnly(DateTime created, string createdBy) :
            base(created, createdBy) 
        {
            throw new Exception("Object is ReadOnly, cannot create a new instance");
        }
     }

基类:

public abstract class ProjectBase<T> : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

            private bool _isActive;

    public bool IsActive 
    { 
        get { return _isActive; } 
        set { SetField(ref _isActive, value,() => IsActive ); } 
    }

    public DateTime Created { get; private set; }
    public string CreatedBy { get; private set; }
    public DateTime? LastUpdated { get; protected set; }
    public string LastUpdatedBy { get; protected set; }
    public bool IsDirty { get; protected set; }

    private ProjectBase() { }

    protected ProjectBase(DateTime created, string createdBy)
    {
        IsActive = true;
        Created = created;
        CreatedBy = createdBy;
        LastUpdated = created;
        LastUpdatedBy = createdBy;
        IsDirty = false;
    }

    public abstract void Clone();
    public abstract void Create();
    public abstract void Update(DateTime lastUpdated, string lastUpdatedBy);
    protected abstract void Update();
    public abstract void Delete();

    protected bool SetField<TField>(ref TField field, TField value, Expression<Func<TField>> selectorExpression)
    {
        bool returnValue = false;

        if (EqualityComparer<TField>.Default.Equals(field, value))
            returnValue = false;
        else
        {
            field = value;
            IsDirty = true;
            OnPropertyChanged(selectorExpression);
            returnValue = true;
        }

        return returnValue;
    }

    protected virtual void OnPropertyChanged<TParam>(Expression<Func<TParam>> selectorExpression)
    {
        MemberExpression body;

        if (selectorExpression == null)
            throw new ArgumentNullException("selectorExpression");

        body = selectorExpression.Body as MemberExpression;

        if (body == null)
            throw new ArgumentException("The body must be a member expression");

        OnPropertyChanged(body.Member.Name);
    }

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
            handler(this, new PropertyChangedEventArgs(name));

        IsDirty = true;
    }

    protected void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        IsDirty = true;
    }

我遇到的问题是使用Owner.CustomerForOwner属性行调用SetField:

SetField(ref _customerForOwner, value, () => CustomerForOwner);

我收到以下编译错误: 无法从用法中推断出方法'ProjectBase.SetField(ref TField,TField,System.Linq.Expressions.Expression&gt;)'的类型参数。尝试明确指定类型参数。

如何通过传递ICustomer作为客户?我把它改为:

SetField(ref _customerForOwner, (Customer)value, () => CustomerForOwner);

但同样的错误。我也尝试在Setter上面的行上面为新客户设置值,但是返回了相同的编译错误。

2 个答案:

答案 0 :(得分:1)

你试过这个:

SetField(ref _customerForOwner, 
    (Customer)value, () => (Customer)CustomerForOwner);

因为CustomerOfOwner是接口类型。

答案 1 :(得分:1)

方法

SetField(ref _customerForOwner, value, () => CustomerForOwner);

类型为单个类型参数(TField),但是

_customerForOwnerCustomervalueICustomerCustomerForOwnerICustomer,因此编译器无法推断出类型,因为,当它试图推断_customerForOwnerICustomer时,必须将具体类型转换为接口。

这是不允许的,因为C#语言规则是:

  

ref或out参数必须是可赋值变量

演员表会导致未分配的变量。

如果你这样做:

public virtual ICustomer CustomerForOwner
{
    get { return _customerForOwner; }
    set 
    {
        var customerForOwner = (ICustomer)_customerForOwner;
        SetField(ref customerForOwner, value, () => CustomerForOwner);
        _customerForOwner = customerForOwner as Customer;
        value.PropertyChanged += this.OnItemPropertyChanged;
    }
}

然后代码将编译。它是否会起作用并做你想做的事,我不确定。代码对我来说有点奇怪。 :)例如,SetField返回一个布尔值,你没有使用它。