【问题标题】:C# How check if object is created in using statement [closed]C#如何检查是否在using语句中创建了对象[关闭]
【发布时间】:2015-08-04 13:30:28
【问题描述】:

我有一个班级 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 语句中创建主要范围时,我想从池中获取新的连接,但是如果我使用我的范围创建嵌套的 using 块,我想使用来自主要范围的连接。嵌套是可行的,因为在可能的主要 using 块中,我可以在我的范围内运行包含另一个 using 块的方法。

【问题讨论】:

  • 不要在构造函数中做事
  • 我不明白这个问题。此外,您正在同一范围内重新定义相同的变量mc
  • 除了是非常糟糕的设计之外,这实际上是不可能的,因为编译器会破坏您的代码并以不同的方式重构它。 using 语句是花哨的 try/finally 自动处理的语法糖。
  • 这只是一个简单的例子来说明我需要做什么,但它可能更复杂,所以我不能调用具体方法,因为我不知道这段代码是否是嵌套与否
  • 你使用你的类的地方应该告诉它如何被构造,你的类不应该试图检测它是如何被使用的,并据此执行不同的逻辑。编译器优化无论如何都会修改代码,因此它在文本编辑器中的编写方式通常不是它的编译方式。如果您需要基于某些东西运行逻辑,则应该将参数传递给您的类。虽然这看起来像 X-Y 问题,但您需要告诉我们您真正想要解决的问题是什么,为什么需要这个。

标签: c# using


【解决方案1】:

您的问题的简单答案是:您不能。 using 是纯语法糖。一个典型的 using 语句:

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

直接翻译成这个:

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

通常,在 .NET 中,通过反映调用堆栈,您无法知道您的代码从何处被调用,超出了函数级别。 [System.Diagnostics][1] 中的 StackFrame 对象会告诉你当前方法的 IL 偏移量,所以我想如果你真的确定你可以拆开当前方法的 IL 并尝试找出你在任何 @987654327 中的位置@code,但这对我来说听起来真的很脆弱和恶心。

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

在我看来,你想要的是某种工厂对象:

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.");
                 });
    }        
}

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

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

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

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);
            }
        }
    }
}

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

public class Tracker {
    private int _level;
    public BeginEnd<int> Track()
    {
        return new BeginEnd<int>(_level++,
            lev1 => {
               Debug.WriteLine("Begin " + lev1);
            },
            lev2 => {
               Debug.WriteLine("End " + lev2);
               --_level;
            });
    }
}

//...
Tracker t = new Tracker();
using (var n0 = t.Track()) {
    using (var n1 = t.Track()) {
    }
    using (var n2 = t.Track()) { }
} 
// prints:
// Begin 0
// Begin 1
// End 1
// Begin 1
// End 1
// End 0

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

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

【讨论】:

    猜你喜欢
    • 2010-10-05
    • 1970-01-01
    • 1970-01-01
    • 2011-05-19
    • 1970-01-01
    • 1970-01-01
    • 2020-12-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多