C# - 在运行时更改属性setter的行为

时间:2015-09-30 13:21:25

标签: c#

我遇到了一个有点人为的编码问题,我希望有人可以告诉我,在标准C#中我能做什么是可能的。

我有一个类,它最初存储了Foo个对象的列表,并对它们进行了更新,如下所示:

public class Program
{
    private List<Foo> listOfFoo;

    ...

    public void SomeMethod()
    {
        var fooObject = (Foo)(listOfFoo[0]);
        fooObject.Name = "name";
        fooObject.Address = "address;"
    }
}

然后,我希望将List<Foo>替换为自定义类FooRepository,该类使用从FooDto生成的Foo类型的对象的支持列表,而不进行任何操作更改调用代码中listOfFoo的使用方式:

public class FooRepository : IEnumerator<Foo>, IEnumerable<Foo>
{
    private List<FooDto> backingList;

    ...

    public void Add(Foo foo)
    {
        backingList.Add(MapToDto(foo));
    }

    public Foo this[int i]
    {
        get
        {
            return MapFromDto(backingList[i]);
        }
    }
    ...
}

但这会导致最初如何在调用代码中执行对象更新的问题,因为现在访问存储库不会返回对支持列表中的实际对象的引用,而是返回新生成的对象。所以我的问题是:保持这个基本设计,而不是在调用代码或Foo本身中修改任何内容,我可以以某种方式修改FooRepository,以便SomeMethod中的更新仍然永久提交到存储库?

我可以在FooRepository中存储两个列表,一个用于FooDto,一个用于Foo,并将Foo列表中的更改提交到{{1}每次有人在存储库上调用方法时,我们假设我不想这样做。似乎我的基本策略是对存储库的所有访问都应返回一个可被视为FooDto的对象,但它还具有将属性赋值提交给后备Foo的附加行为。如果C#支持任意运行时猴子修补,我可以做类似的事情:

FooDto

但事实并非如此。我想过使用System.Reflection.Emit生成一个新的子类public Foo this[int i] { get { return MapFromDto(backingList[i]).ForAllProperties(property => { property.NewSetter(value => backingList[i].property = value; ...); } } } 来覆盖属性setter,但Foo中的所有属性都没有标记为虚拟,所以我相信不能完成。我可以构造一个动态对象来实现Foo中的所有内容以及新的setter行为,并使用像ImpromptuInterface这样的库将动态对象视为实现某个接口,但Foo不实现任何接口;这些属性只是在类本身中编码。

似乎是在不修改调用代码或Foo的情况下实现我想要的唯一方法就像this那样修改Foo方法的IL代码在运行时。我有这个权利吗?我忽略了任何选择吗?

感谢。

0 个答案:

没有答案