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>)'の型引数を使用法から推測できません。タイプ引数を明示的に指定してみてください。
パスICustomerを顧客として渡すにはどうすればよいですか?私はそれを次のように変更することにしました:
SetField(ref _customerForOwner, (Customer)value, () => CustomerForOwner);
しかし、同じエラー。また、セッターの上の行で新しい顧客に値を設定しようとしましたが、同じコンパイルエラーが返されました。