1

我在一个名为 Owner 的类上有一个名为 CustomerForOwner 的属性。我想要 Owner 类的只读版本,所以我创建了一个名为 OwnerReadOnly 的包装类。我遇到的问题是当我有引用类型属性时。为了创建该对象的只读版本,我使用了一个接口,以便 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>)' 的类型参数。尝试明确指定类型参数。

我怎样才能通过 ICustomer 作为客户?我将其更改为:

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

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

4

2 回答 2

1

你有没有试过这个:

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

因为CustomerOfOwner是接口类型。

于 2012-10-26T18:13:17.807 回答
1

方法

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

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

_customerForOwneris a Customer, valueis anICustomerCustomerForOwneris an ICustomer,因此编译器无法推断类型,因为当它试图推断它时,_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返回一个你没有使用的布尔值。

于 2012-10-26T18:20:29.217 回答