首先要注意的是 - 我知道代表和装饰图案!
第二 - 我正在使用C#.NET 4.0,所以如果你想出一个特定于它的解决方案,那很好。但是,如果解决方案适用于任何OOP语言和平台,那就太棒了。
这里的问题是......
我有一个部分类(让我们命名为Class1
),我无法修改。因此,我可以扩展它或/并继承它。这个类为我提供了一个完美的数据模型,我唯一需要的是为它的属性添加一些属性(用于验证,在MVC中定义标签文本值等等 - 现在,我不需要答案,比如'你能做什么你需要没有属性',这不是我的问题)。
将另一个类用作数据模型不是问题,因此我可以创建Class2 : Class1
并使用Class2
作为模型。需要属性的属性将定义为public new <type> <propertyname>
。这将限制我仅重写需要属性的属性,而保留所有其他属性。
较小的问题是我没有重新定义属性的getter和setter,因为它们包含的所有内容都是return base.<propertyname>
和base.<propertyname> = value
,如果有很多这样的属性,这意味着很多“愚蠢”的编码。有没有办法避免这种情况?
更大的问题是我必须使用Class2
实例对我的Class1
进行参数化,并为我拥有的每个属性制作类似class2.<propertyname> = class1.<propertyname>
的内容 - 过多的“愚蠢”编码。我可以使用反射来避免它 - 在Class1
中找到包含公共getter和setter的所有属性,并在循环中调用prop.SetValue(child, prop.GetValue(parent, null), null);
。这为简单的情况提供了一个通用函数,这很好,因为我大多数都有简单的模型 - 很多属性与公共getter和setter没有body和另一个逻辑。但我想要更通用的解决方案,我不喜欢反思。有什么想法吗?
以下是基于Class2
Class1
的扩展方法的完整代码
public static Child ToExtendedChild<Parent, Child>(this Parent parent)
where Child : Parent, new()
{
Child child = new Child();
var props = typeof(Parent).GetProperties().Where(p => p.GetAccessors().Count() >= 2);
foreach (var prop in props)
{
prop.SetValue(child, prop.GetValue(parent, null), null);
}
return child;
}
(顺便说一句,这种方法可能无法实现我的解决方案,所以任何更正也会受到赞赏)
提前致谢!
答案 0 :(得分:2)
较小的问题似乎不是什么大问题。也许我误解了这个问题,但假设你只是在推导一个子类,那么就没有理由重新定义属性或它们相关的getter / setter。
更大的问题可能会使用更简单的东西来解决。对很多对象初始化使用反射似乎有点贵。如果您正在处理主要是大包或属性的类,也许您应该在任何给定情况下都需要访问所有这些属性。你提到MVC和验证,你正在验证的控制器方法中使用的整个模型是什么?如果没有,为什么不考虑使用只暴露那个方法所需的那些部分的viewmodel?
你的反射初始化器很有意思,但是如果你要做很多这样的话,你可以考虑用Automapper投入一点时间。否则,可以考虑从通用解决方案转向仅解决手头问题的方法,即将属性从对象实例映射到派生对象的另一个实例。也许你可以在父类中创建一个复制构造函数并在派生类中使用它?
public class Foo {
public string PropOne { get; set; }
public string PropTwo { get; set; }
public Foo(string propOne, string propTwo) {
PropOne = propOne;
PropTwo = propTwo;
}
public Foo(Foo foo) {
PropOne = foo.PropOne;
PropTwo = foo.PropTwo;
}
}
public class Pho : Foo {
// if you have additional properties then handle them here
// and let the base class take care of the rest.
public string PropThree { get; set; }
public Pho(string propOne, string propTwo, string propThree)
: base(propOne, propTwo) {
PropThree = propThree;
}
public Pho(Pho pho) : base(pho) {
PropThree = pho.PropThree;
}
// otherwise you can just rely on a copy constructor
// to handle the initialization.
public Pho(Foo foo) : base(foo) {}
}
答案 1 :(得分:1)
我假设部分类是生成的代码,它在你的场景中最有意义。
我知道有一种方法可以执行此操作,但根据属性的爬网方式,它可能无效。
// Generated Code
public partial Class1
{
public string Foo { get { ... } }
}
// Your Code
public interface IClass1
{
[MyAttribute]
public string Foo { get; }
}
public partial Class1 : IClass1
{
}
如果有人通过使用带继承的GetCustomAttributes来查看属性,那么我认为他们会得到这个属性。
顺便说一句,每当我看到生成的代码没有虚拟属性时,它就会让我内心哭泣。
为了解决您的更大问题,为什么不让Class2成为Class1的包装器。您可以在构造函数中为Class2提供Class1实例,而不是复制所有属性,而是将其存储在本地并使所有属性成为传递。这意味着一些手动编码,但是如果你手动构建一个Class2并想用一堆属性来装饰它,那么,无论如何你都在编写Class2。