C#如何检查是否在using语句中创建了对象

时间:2015-08-04 13:30:28

标签: c# using

我有一个MyClass类。我想在using语句中创建MyClass实例并在构造函数中操作1,但是如果实例创建为嵌套在using语句中与MyClass的其他实例我想做某事2.我不知道如何检查它。我想到了静态类,它检查当前代码语句是否使用了MyClass的其他实例的语句进行了整理,但我不知道如何检查它。

public class MyClass : IDisposable
{
    public MyClass()
    {
        if(condition)
        //do something 1
        else
        //do something 2
    }

    public void Dispose()
    {
        //do something
    }
}

        using (var mc = new MyClass()) //do something 1 in constructor
        {
            using (var mc1 = new MyClass()) //do something 2 in constructor
            {
                 using (var mc2 = new MyClass()) //do something 2 
                 {
                 }
            }
            using (var mc3 = new MyClass()) //do something 2 in constructor
            {
            }

编辑: 我尝试做某种范围。它应该是TransactionScope的一个更大的范围。在我的范围内,我希望有fiew TransactionScopes。我想在整个范围内使用与数据库相同的连接而不将其返回到连接池。因此,当我在using语句中创建主要作用域时,我希望从池中获取新的连接,但如果我使用我的作用域的块创建嵌套,我想使用主要作用域的连接。嵌套是可能的,因为在主要的使用块我可以运行包含另一个使用块的方法与我的范围。

1 个答案:

答案 0 :(得分:3)

你的问题的简单答案是:你不能。 using是纯粹的语法糖。典型的使用陈述:

using (MyDisposableClass a = GetMyDisposableClass())
{
   // ...
}

直接翻译成:

MyDisposableClass a = null;
try {
    a = GetMyDisposableClass();
    // ...
}
finally {
    if (a != null) a.Dispose();
}

一般情况下,在.NET中,您无法通过反映callstack来了解您的代码被调用的功能超出了函数级别。来自StackFrame的{​​{1}}对象会告诉你当前方法的IL偏移量,所以我想如果你真的确定你可以拆分当前方法的IL并尝试找出你的位置在任何[System.Diagnostics][1]代码中,但这听起来对我来说真的很脆弱。

你到底想要做什么,你觉得你必须像这样管理它?

对我来说,感觉就像你想要的是某种工厂对象:

try/finally

这样做是建立一个工厂,将构造函数隐藏到MyClass并公开一个工厂方法来生成可以使用的IMyClass对象。它执行严格的排序,以便按顺序构造和处理对象,这或多或少地满足您的嵌套要求。如果您愿意,可以根据对象使对象做不同的事情。

我仍然会犹豫是否使用此代码。它感觉不对,但只要你每个方法只使用一个工厂,至少做错事情会更难。

我猜你真正想要做的是在跟踪嵌套的代码块中有开始/结束语义,但是你希望编译器为你管理它。我已经完成了一个需要调用两个函数的对象,一个在开始,一个在结束:

public interface IMyClass { int Level { get; } } // whatever
public class MyClassFactory {
    private delegate void Notifier(int level);
    public class MyClass : IDisposable
    {
        public MyClass(int level, Notifier notifier)
        {
           _level = level;
           _notifier = notifier;
        }
        private int _level;
        private Notifier _notifier;   
        ~MyClass() { Dispose(false); }
        public int Level { get { return level; } }
        public Dispose() { Dispose(true); GC.SuppressFinalize(this); }
        private bool _disposed = false;
        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed) {
                if (disposing) {
                    notifier(Level);
                    _disposed = false;
                }
                else { throw new Exception("My class used outside using block."); }
            }
        }
    }

    private int _level = 0;

    public IMyClass Make()
    {
        return new MyClass(_level++,
                childLevel => {
                   if (childLevel == _level)
                       --_level;
                   else throw new Exception("Disposed out of order.");
                 });
    }        
}

然后可以在这样的上下文中使用:

public class BeginEnd<T> : IDisposable
{
    private Action<T> _end;
    private bool _disposed;
    private T _val;
    public BeginEnd(T val, Action<T> begin, Action<T> end)
    {
        _end = end;
        _val = val;
        begin(val);
    }
    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    ~BeginEnd() { Dispose(false); }
    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed) {
            if (disposing) {
              _disposed = true;
              _end(_val);
            }
        }
    }
}

通过强制执行开始/结束规则来正确跟踪使用块的嵌套。

这是否是对语言结构的恰当使用一直存在争议before。我觉得你的问题可以通过另一种更合适的方式解决。