4

所以这里的问题是:有没有办法创建一个只共享一部分代码的上下文。我真的不知道如何解释,所以我举个例子。

假设我有:

using(Context ctx = new Context())
{
    ctx.Set("abc","abc");
    method1();
    method2();
}

和(与方法 2 相同):

public void method1()
{
    Context ctx = Context.Instance();
    string abc = ctx.Get("abc");
}

目标是Context.Instance()in 方法返回在 using 中创建的对象,但它必须保持线程安全。我的意思是,如果从一个 using 外部或同时在另一个 using 内部进行调用,它将根据 using 返回上下文。如果不存在,Context.Instante()将返回一个新的Context(或 null,我会在之后适应,这不是重点)。

我知道这不是经典的做法,但我不想在每次调用时都传递上下文。真正的方法会有很多 subs 方法,只有 lasts 需要它,但它必须从一开始就很常见。

目标是创建一个将共享给所有(且仅)子方法的事务,但顶级方法无权访问 EF 类。我唯一的解决方案是使用会话来存储我的 EF 上下文,或者在批处理中使用静态,因为它们没有会话。这是我的目标,但问题更为笼统。

我希望我很清楚,不要犹豫,问问题。并添加标签,因为我真的不知道添加了什么标签。

谢谢 !

编辑

我可能还不够清楚。单例是不够的,静态是在所有实例之间共享的。如果两个不同的用户同时对 using 进行两次调用,则上下文对他们来说是相同的,但我希望它们不同。

理想情况下,我想允许这样的事情:

using(Context ctx = new Context())
{
    ctx.Set("abc","abc");
    method1();
    using(Context ctx = new Context())
    {
        ctx.Set("abc","def");
        method2();
    }
    method1();
}

但我觉得我要求的太多了。

4

3 回答 3

3

让您的 Context.Instance() 方法管理线程静态变量。第一个调用可以创建实例,其他调用可以使用它,并且在第一个调用的使用结束时,您将其销毁。

使用线程静态方法,不会出现多线程问题,因为每个线程都有自己的实例。在单个线程中,每个“下一个方法执行”都将使用相同的实例。

更新:

一些代码。如果我通过它进行调试,则只创建一个上下文,第二个 using 语句接收与第一个 using 语句相同的上下文。

class Context : IDisposable {
    [ThreadStatic]
    private static Context _instance;
    [ThreadStatic]
    private static int _instanceCounter;

    public static Context Instance() {
        if (_instanceCounter == 0) {
            _instance = new Context();
        }
        _instanceCounter++;
        return _instance;
    }

    private static void Release() {
        _instanceCounter--;
        if (_instanceCounter == 0) {
            if (_instance != null)
                _instance.Dispose();
            _instance = null;
        }
    }

    public void Dispose() {
        Release();
    }
}

public class Test {
    public void Test1() {
        using (var context = Context.Instance()) {
            // do something
            Test2();
        }
    }

    private void Test2() {
        using (var context = Context.Instance()) {
            // identical context as in Test1
            // do something
        }
    }
}
于 2012-08-21T13:25:33.400 回答
0

如果你想要 Singleton 设计模式,这里有一个模板。它将确保只创建一个类的实例,并且程序的所有部分都使用相同的实例

public class Singleton {

 private static Singleton instance; 

 private Singleton(){ // note private constructor

  // intialize code here
 }


 public static Singleton GetInstance(){

  if(instance == null){

   instance = new Singleton();
 }
   return instance;
 }

}

}

同样在多线程环境中,您可能需要想象这样一种情况,当 Instance 为空时,两个线程可以进入您的 GetInstance 方法,并且最终都初始化 Singleton 类的单独实例。

要检索您将调用的实例Singleton.GetInstance()

于 2012-08-21T13:24:55.267 回答
0

正如 Maarten 所说,您需要使用 ThreadStatic,这样的事情可能会起作用:

public class Context : IDisposable
{
    [ThreadStatic]
    private static Context context;

    private Context(Guid id)
    {
        this.Id = id;
    }

    public Guid Id
    {
        get;
        private set;
    }

    public static Context Instance()
    {
        if (context == null)
        {
            context = new Context(Guid.NewGuid());
        }

        return context;
    }

    public void Dispose()
    {
        context = null;
    }
}

如果您创建一个包含以下代码的控制台应用程序,您应该了解它是如何工作的。

private static void Main(string[] args)
{
    Action action = () =>
    {
        using (var context = Context.Instance())
        {
            Console.WriteLine("Thread {0} - Context Id {1}", Thread.CurrentThread.ManagedThreadId, context.Id);

            using (var context2 = Context.Instance())
            {
                Console.WriteLine("Thread {0} - Context Id {1}", Thread.CurrentThread.ManagedThreadId, context.Id);
            }
        }

        Thread.Sleep(1000);
    };

    Task.Factory.StartNew(action);
    Task.Factory.StartNew(action);

    Console.ReadLine();
}

如果要确保上下文仅由最外层的 using 语句实际处理,则还需要计算每个线程调用实例的次数。

于 2012-08-21T13:44:28.080 回答