我現有的類結構。使用泛型基本抽象類方法訪問子類對象
AbstractTradeBaseClass - > AbstractTradeClass - > ConcreteTradeClass。
我使用DataAnnotations和IDataErrorInfo來驗證我的模型在我的WPF應用程序。 我已將IDataErrorInfo方法移至AbstractTradeBaseClass,以便我可以使用所有從基類繼承的類。
這是通過使用Linq動態讀取屬性來完成的。
AbstractTradeBaseClass.cs
public abstract class TradeBaseModel<T> : INotifyPropertyChanged, IDataErrorInfo
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
# region Getter/Validator members for Annotations
private static readonly Dictionary<string, Func<T, object>>
propertyGetters = typeof(T).GetProperties()
.Where(p => GetValidations(p).Length != 0)
.ToDictionary(p => p.Name, p => GetValueGetter(p));
private static readonly Dictionary<string, ValidationAttribute[]> validators =
typeof(T).GetProperties()
.Where(p => GetValidations(p).Length != 0)
.ToDictionary(p => p.Name, p => GetValidations(p));
private static ValidationAttribute[] GetValidations(PropertyInfo property)
{
return (ValidationAttribute[])property.GetCustomAttributes(typeof(ValidationAttribute), true);
}
private static Func<T, object> GetValueGetter(PropertyInfo property)
{
var instance = Expression.Parameter(typeof(T), "i");
var cast = Expression.TypeAs(Expression.Property(instance, property), typeof(object));
return (Func<T, object>)Expression.Lambda(cast, instance).Compile();
}
# endregion
#region IDataErrorInfo Members
public string Error
{
get
{
var errors = from i in validators
from v in i.Value
where !v.IsValid(propertyGetters[i.Key](**(T)ModelToValidate()**))
select v.ErrorMessage;
return string.Join(Environment.NewLine, errors.ToArray());
}
}
protected Dictionary<string, string> _errors = new Dictionary<string, string>();
public IDictionary<string, string> Errors
{
get { return _errors; }
}
public string this[string columnName]
{
get
{
string errorMessage = string.Empty;
this.Errors.Remove(columnName);
//string errorMessage = string.Empty;
//switch(columnName)
//{
// case "Range":
// if (Range > 15)
// {
// errorMessage = "Out of Range, should be less than 15";
// }
// break;
//}
//return errorMessage;
if (propertyGetters.ContainsKey(columnName))
{
var value = propertyGetters[columnName](**(T)ModelToValidate()**);
var errors = validators[columnName].Where(v => !v.IsValid(value))
.Select(v => v.ErrorMessage).ToArray();
string error = string.Join(Environment.NewLine, errors);
this.OnPropertyChanged("Error");
if (!string.IsNullOrEmpty(error))
{
this.Errors.Add(columnName, error);
}
return error;
}
return string.Empty;
}
}
public abstract object ModelToValidate(); -- ***Gets the child object here, overridden in the child class to return the child object, -- is there a better way to do this using Generics ??***
#endregion
}
AbstractTradeClass
public abstract class TradeClassBase<T> : TradeBaseModel<T>
{
public string EmptyString
{
get { return string.Empty; }
}
}
ConcreteTradeClass
public class CashFlowTrade : TradeClassBase<CashFlowTrade>
{
private int range;
[RangeAttribute(0,10, ErrorMessage="Out of Range, Range should be less than 15")]
public int Range
{
get
{
return this.range;
}
set
{
if (this.range != value)
{
this.range = value;
this.OnPropertyChanged("Range");
}
}
}
public override object ModelToValidate()
{
return this;
}
}
是否有更好的方法來做到這一點,而不是使用抽象方法並在子類中重寫它以傳遞實際的子類對象並將其轉換爲類型T. 以上代碼以BOLD表示。
如果有方法可以將子類對象傳遞給基類,那麼我可以使用實際的子類對象本身來執行驗證操作。
更新工作守則 約束T,帶類,並使用類型轉換操作如下。
public abstract class TradeBaseModel<T> : INotifyPropertyChanged, IDataErrorInfo
where T : class
替換呼叫到與鑄型的抽象方法。
if (propertyGetters.ContainsKey(columnName))
{
var value = propertyGetters[columnName](this as T);
非常棒的KeK,你讓我在正確的方向思考。 我試過(這個),但是有一個類型不匹配的錯誤,因爲T是一個派生類型,這將涉及基類型,所以VS也不喜歡它,所以這次採取了不同的方法。 將基類和派生類約束到Where T:類,然後使用as運算符對此進行類型化,這似乎工作。 所以主要是什麼不同之間的(T)這和(這是T),前者給出了一個錯誤,不能被施放,但後來的作品,我猜這一切都歸結爲協方差,原則.. – Kans 2012-07-12 12:27:03
行...我想我並不完全理解這個含義。請參閱經過編輯的答案,解決方法是避免as運算符 – Kek 2012-07-12 12:57:59
這不起作用,因爲T是派生類型,因爲它在字典中 - Func,當執行此操作的(T)時,轉換無效,所以仍然會遇到類型不匹配時使用此約束T到我的基類型後... –
Kans
2012-07-12 13:13:25