我在名为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上面的行上面为新客户设置值,但是返回了相同的编译错误。
答案 0 :(得分:1)
你试过这个:
SetField(ref _customerForOwner,
(Customer)value, () => (Customer)CustomerForOwner);
因为CustomerOfOwner
是接口类型。
答案 1 :(得分:1)
方法
SetField(ref _customerForOwner, value, () => CustomerForOwner);
类型为单个类型参数(TField
),但是
_customerForOwner
是Customer
,value
是ICustomer
而CustomerForOwner
是ICustomer
,因此编译器无法推断出类型,因为,当它试图推断_customerForOwner
是ICustomer
时,必须将具体类型转换为接口。
这是不允许的,因为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
返回一个布尔值,你没有使用它。