1

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);

しかし、同じエラー。また、セッターの上の行で新しい顧客に値を設定しようとしましたが、同じコンパイルエラーが返されました。

4

2 に答える 2

1

方法

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

TFieldただし、型は単一の型パラメーター ( ) を取ります。

_customerForOwnerは でありCustomer、 でvalueありICustomerCustomerForOwnerである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使用していないブール値を返します。

于 2012-10-26T18:20:29.217 に答える
1

これを試しましたか:

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

CustomerOfOwnerインターフェイス型だからです。

于 2012-10-26T18:13:17.807 に答える