如何在基类中获得派生类的属性?
基类:
public abstract class BaseModel {
protected static readonly Dictionary<string, Func<BaseModel, object>>
_propertyGetters = typeof(BaseModel).GetProperties().Where(p => _getValidations(p).Length != 0).ToDictionary(p => p.Name, p => _getValueGetter(p));
}
派生类:public class ServerItem : BaseModel, IDataErrorInfo {
[Required(ErrorMessage = "Field name is required.")]
public string Name { get; set; }
}
public class OtherServerItem : BaseModel, IDataErrorInfo {
[Required(ErrorMessage = "Field name is required.")]
public string OtherName { get; set; }
[Required(ErrorMessage = "Field SomethingThatIsOnlyHereis required.")]
public string SomethingThatIsOnlyHere{ get; set; }
}
在这个例子中-我可以从ServerItem类中获得"Name"属性,而在BaseModel类?
编辑:我试图实现模型验证,如下所述:http://weblogs.asp.net/marianor/archive/2009/04/17/wpf-validation-with-attributes-and-idataerrorinfo-interface-in-mvvm.aspx
我认为,如果我创建一些基本模型(几乎)所有的验证魔术在它,然后扩展该模型,它将是好的…
如果两个类都在同一个程序集中,您可以尝试这样做:
Assembly
.GetAssembly(typeof(BaseClass))
.GetTypes()
.Where(t => t.IsSubclassOf(typeof(BaseClass))
.SelectMany(t => t.GetProperties());
这将给你BaseClass
的所有子类的所有属性。
如果您要求派生类必须实现一个方法或属性,您应该将该方法或属性作为抽象声明引入基类。
例如,对于Name
属性,您可以在基类中添加:
public abstract string Name { get; set; }
那么任何派生类必须实现它,或者自己是抽象类。
一旦你把Name
属性的抽象版本添加到基类中,你就可以在基类的任何地方访问它,除了在基类的构造函数中。
如果您必须从基类中获取派生类的属性,您可以使用反射,例如-像这样…
using System;
public class BaseModel
{
public string getName()
{
return (string) this.GetType().GetProperty("Name").GetValue(this, null);
}
}
public class SubModel : BaseModel
{
public string Name { get; set; }
}
namespace Test
{
class Program
{
static void Main(string[] args)
{
SubModel b = new SubModel();
b.Name = "hello";
System.Console.Out.WriteLine(b.getName()); //prints hello
}
}
}
这是不推荐的,但你很可能应该重新考虑你的设计,就像马修说的。
至于不向基类抛出属性——你可以尝试将基类和派生类解耦为不相关的对象,并通过构造函数传递它们。
另一种解决方法是在基类中创建虚拟属性,并在派生类中重写。
public class Employee
{
public virtual string Name {get; set;}
}
public class GeneralStaff
{
public override string Name {get; set;}
}
class Program
{
static void Main(string[] args)
{
Employee emp = new GeneralStaff();
emp.Name = "Abc Xyz";
//---- More code follows----
}
}
好了,我解决这个问题的方法与这篇文章的作者略有不同:http://weblogs.asp.net/marianor/archive/2009/04/17/wpf-validation-with-attributes-and-idataerrorinfo-interface-in-mvvm.aspx
public abstract class BaseModel : IDataErrorInfo {
protected Type _type;
protected readonly Dictionary<string, ValidationAttribute[]> _validators;
protected readonly Dictionary<string, PropertyInfo> _properties;
public BaseModel() {
_type = this.GetType();
_properties = _type.GetProperties().ToDictionary(p => p.Name, p => p);
_validators = _properties.Where(p => _getValidations(p.Value).Length != 0).ToDictionary(p => p.Value.Name, p => _getValidations(p.Value));
}
protected ValidationAttribute[] _getValidations(PropertyInfo property) {
return (ValidationAttribute[])property.GetCustomAttributes(typeof(ValidationAttribute), true);
}
public string this[string columnName] {
get {
if (_properties.ContainsKey(columnName)) {
var value = _properties[columnName].GetValue(this, null);
var errors = _validators[columnName].Where(v => !v.IsValid(value)).Select(v => v.ErrorMessage).ToArray();
return string.Join(Environment.NewLine, errors);
}
return string.Empty;
}
}
public string Error {
get { throw new NotImplementedException(); }
}
}
也许它会帮助别人。
扫描程序集中所有从BaseModel继承的类,并创建如下的字典:
Dictionary<Type, Dictionary<string, Func<BaseModel, object>>>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TESTNEW
{
public abstract class BusinessStructure
{
public BusinessStructure()
{ }
public string Name { get; set; }
public string[] PropertyNames{
get
{
System.Reflection.PropertyInfo[] Pr;
System.Type _type = this.GetType();
Pr = _type.GetProperties();
string[] ReturnValue = new string[Pr.Length];
for (int a = 0; a <= Pr.Length - 1; a++)
{
ReturnValue[a] = Pr[a].Name;
}
return ReturnValue;
}
}
}
public class MyCLS : BusinessStructure
{
public MyCLS() { }
public int ID { get; set; }
public string Value { get; set; }
}
public class Test
{
void Test()
{
MyCLS Cls = new MyCLS();
string[] s = Cls.PropertyNames;
for (int a = 0; a <= s.Length - 1; a++)
{
System.Windows.Forms.MessageBox.Show(s[a].ToString());
}
}
}
}