替代传递上下文对象的方法

3

我有一个单一的上下文对象,我希望能够从许多不同的类中访问它。我的代码看起来像这样:

Context ctx = new Context();
Section section = new Section(ctx) {
    Data1 = new SomeData(ctx) { Value = 123 },
    Data2 = new SomeOtherData(ctx) { Foo = "bar" },
    SubSection = new Section(ctx) {
        MoreData = new MoreData(ctx) { Text = "Hello!" }
    }
};

但我真正想要的是看起来像这样的代码:

using(Context.New()) {
    Section section = new Section() {
        Data1 = new SomeData { Value = 123 },
        Data2 = new SomeOtherData { Foo = "bar" },
        SubSection = new Section {
            MoreData = new MoreData { Text = "Hello!" }
        }
    };
    // do something with section
}

这可行吗?我将在ASP.NET以及.exe文件中使用它(可能还会有其他东西),所以无法仅将静态或线程本地引用存储在某个位置。它不需要与上述完全相同,只需一种方式即可,这样我就不必将上下文传递给我创建的每个对象。我考虑过使用类似于“context.createSomeData()”的扩展方法,但是每个类都需要更多的样板文件,并且与您仍然需要上下文对象相比,并没有任何改进。理想情况下,应该在VS2008/.NET3.5下运行,尽管如果有任何方法可以做到这一点,我仍然会感兴趣。更新:最终通过重新设计我的方法解决了此问题,具体如下:
Section section = new Section {
    Data1 = new SomeData { Value = 123 },
    Data2 = new SomeOtherData { Foo = "bar" },
    SubSection = new Section {
        MoreData = new MoreData { Text = "Hello!" }
    }
};
section.DoStuffWithContext(new Context());

虽然这可能并不适用于每个人,但它能满足我在此处的需求。如果有人提出了解决最初问题的好方法,我会让这个问题保持开放状态。

2
new Section(ctx) { Data1 = new SomeData { ... }, Data2 = new SomeOtherData { ... }, ... } 这样写可以吗?如果可以的话,你可以修改 Section 类的属性设置器,将上下文传递给分配的值。 - user743382
这是一个很好的观点,虽然那会有很多样板文件。我希望他人能够创建扩展这些类的类;现在必须使用单行构造函数,尽管足够简单,但为每个属性定义复杂的设置器还是有点过头了。 - Jussi Kosunen
3个回答

2
您可以定义一个静态方法Context.RetreiveData(),但您不必在方法本身内部实现任何样板代码。
使用命令模式,每个特定的项目类型都可以为RetreiveData()方法提供自己的实现。ASP.NET项目可以提供一个从Session中检索数据的方法。WinForm可执行文件可以提供一个从某个全局变量中检索数据的方法。另一个项目可以提供一个从数据库中检索数据的方法。

这会打破解耦和封装,超出我在这个特定项目中感到舒适的范围。假设有.exe文件A和.dll文件B和C,其中A引用了B并且B引用了C——当C中定义了"上下文"时,我们需要在A中实现这个额外的代码。这可能看起来过于追究,但考虑到我们使用和分发这些库的方式,这是不可行的。不过这是个好主意。 - Jussi Kosunen

1
不,没有明显的可能性。您甚至使用了对象初始化程序(new Obj { ... }),因此需要使用new运算符(这使得使用ctx的静态方法/扩展方法变得不可能)。
您唯一能做的事情是:
SomeData MakeSomeData(this Context ctx, int value)
{
    return new SomeData(ctx) { Value = value };
}

在初始化中:
Context ctx = new Context();

Section section = new Section(ctx) {
    Data1 = ctx.MakeSomeData(123), ...

但我认为你不会得到任何好处。

是的,数据类型非常稀疏,所以我需要在扩展方法中定义可能有数十个参数,其中我只会使用一两个。如果我使用命名参数(需要VS2010),那么调用不会很麻烦,但正如你所说,我真的不会获得任何好处。 - Jussi Kosunen

0

我赞同hvd在你的问题上的评论,而且我认为它不需要太多的样板代码。假设每个类实现了这个:

public interface IContextConsumer {
    Context Context { get; set; }
}

而你的基类有一个像这样的方法:

protected void AddChild(IContextConsumer child) {
    child.Context = this.Context;
}

属性的实现只需要:

private SomeData _data1;
public SomeData Data1 {
    get { return _data1; }
    set {
        _data1 = value;
        AddChild(_data1);
    }
}

如果你像这样做:

你甚至可以允许重新分配根上下文。

protected void AddChild(IContextConsumer child) {
    Children.Add(child);
    child.Context = this.Context;
}

protected void OnContextChanged() {
    foreach (var child in Children) child.Context = this.Context;
}

派生类只需要在它们的“Context”属性实现中调用OnContextChanged即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接