[英]What is an elegant way to aggregate properties from subclasses in C#?
I have a situation where I am mapping classes that have an inheritance hierarchy. 我有一种情况,我正在映射具有继承层次结构的类。 I have a list of items that each class knows that it needs.
我有一个每个类都知道它需要的项目列表。 For example:
例如:
public class PersonMapper
{
private string[] attributes = new[] {"firstName", "lastName"};
}
public class UserMapper : PersonMapper
{
private string[] attributes = new[] {"username"};
}
public class EmployeeMapper : PersonMapper
{
private string[] attributes = new[] {"employeeId"};
}
I would like to make a method call that returns the aggregate of all of the super classes like this: 我想进行一个方法调用,返回所有超类的聚合,如下所示:
EmployeeMapper mapper = new EmployeeMapper();
string[] attributes = mapper.GetAttributes();
Assert.That(attributes, Has.Member("firstname"));
I can think of some solutions, but they seem overly complicated. 我可以想到一些解决方案,但它们似乎过于复杂。 I feel like there is an elegant solution to this that I am missing.
我觉得有一个优雅的解决方案,我错过了。 Can anyone help?
有人可以帮忙吗?
Thanks in advance! 提前致谢!
You can have a virtual method/property on the superclass called GetAttributes that returns the private array. 您可以在名为GetAttributes的超类上拥有一个返回私有数组的虚方法/属性。 Then, in each subclass, override it like so.
然后,在每个子类中,像这样重写它。 First call the base GetAttribute method to get the base classes array, and the combine that with the subclasses array, and return the new array.
首先调用基本GetAttribute方法以获取基类数组,以及与子类数组的组合,并返回新数组。
Code sample: 代码示例:
public class PersonMapper
{
private string[] attributes = new[] { "firstName", "lastName" };
public virtual string[] GetAttributes()
{
return attributes;
}
}
public class EmployeeMapper : PersonMapper
{
private string[] attributes = new[] { "employeeId" };
public override string[] GetAttributes()
{
return base.GetAttributes().Union(this.attributes).ToArray();
}
}
I'd be tempted to develop a custom attribute that gets applied to each of the properties that I care to track and then use reflection to enumerate the properties with that attribute applied. 我很想开发一个自定义属性,该属性应用于我要跟踪的每个属性,然后使用反射来枚举应用了该属性的属性。 You could use lazy loading so that the attribute list only gets populated once.
您可以使用延迟加载,以便仅填充一次属性列表。 I'd also probably make GetAttributes() a static (class) method.
我也可能使GetAttributes()成为一个静态(类)方法。
public class MappedAttribute : Attribute
{
}
public class Person
{
[Mapped]
public string FirstName { get; set; }
[Mapped]
public string LastName { get; set; }
public string DisplayName
{
get { return FirstName + " " + LastName; }
}
}
public static class Mapper
{
public static IList<string> Attributes( Type t )
{
List<string> attributes = new List<string>();
foreach (PropertyInfo pInfo in t.GetProperties())
{
MappedAttribute attr = pInfo.GetCustomAttributes(typeof(MappedAttribute),false)
.Cast<MappedAttribute>()
.FirstOrDefault();
if (attr != null)
{
attributes.Add(pInfo.Name);
}
}
return attributes;
}
}
Without reflection, there is no way to do it in the current state. 如果没有反射,就无法在当前状态下执行此操作。 What you could do though is make a protected virtual method which allows each class to add their attributes to a list and aggregate that way.
你可以做的是制作一个受保护的虚拟方法,它允许每个类将它们的属性添加到列表中并以这种方式聚合。
public class PersonMapper {
protected virtual void AggregateAttributes(List<string> list) {
list.AddRange(attributes);
}
public List<string> GetAttributes() {
List<string> list = new List<string>();
AggregateAttributes(list);
return list;
}
}
public class UserMapper {
protected override void AggergateAttributes(List<string> list) {
base.AggregateAttributes(list);
list.AddRange(attributes);
}
}
public class EmployeeMapper {
protected override void AggergateAttributes(List<string> list) {
base.AggregateAttributes(list);
list.AddRange(attributes);
}
}
I would go for a simpler approach: 我会采取更简单的方法:
class Entity {
public virtual IEnumerable<string> Attributes { get { yield return "Name"; } }
}
class Person : Entity {
public override IEnumerable<string> Attributes {
get {
return new string[] { "FirstName", "LastName" }
.Concat(base.Attributes);
}
}
}
class User : Person {
public override IEnumerable<string> Attributes {
get {
return new string[] { "UserName" }
.Concat(base.Attributes);
}
}
}
(PS These kinds of hierarchies rarely work out in single-inheritance languages.) (PS这些层次结构在单继承语言中很少有用。)
public class PersonMapper
{
protected List<string> attributes =
new List<string>() {"firstName", "lastName"};
public string[] GetAttributes()
{
//defensive copy
return attributes.ToArray();
}
}
public class EmployeeMapper : PersonMapper
{
public EmployeeMapper()
{
attributes.Add("employeeId");
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.