为部分代码创建上下文

时间:2012-08-21 13:16:52

标签: c# session

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

假设我有:

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()返回在使用中创建的对象,但它必须保持线程安全。我的意思是如果调用是从外部使用,或在另一个内部同时使用,它将根据使用返回上下文。如果不存在,Context.Instante()将返回一个新的Context(或者null,我将在之后进行调整,这不是重点)。

我知道这不是经典的做法,但我不想在每次通话时传递上下文。真正的方法将有很多子方法,只有持续时间需要它,但它从一开始就必须是常见的。

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

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

谢谢!

修改

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

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

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

但我想我问得太多了。

3 个答案:

答案 0 :(得分:3)

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

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

更新:

一些代码。如果我通过它调试,只创建一个上下文,第二个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
        }
    }
}

答案 1 :(得分: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为null时两个线程可以进入GetInstance方法的情况,并且最终都会初始化Singleton类的单独实例。

要检索实例,您可以调用Singleton.GetInstance()

答案 2 :(得分:0)

你需要使用ThreadStatic,就像Maarten所说,这样的事情可能有用:

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语句实际处理,则需要计算每个线程调用实例的次数。