English 中文(简体)
在使用环体内的例外情况下发现处置
原标题:Detecting a Dispose() from an exception inside using block

我应用了以下法典:

using (var database = new Database()) {
    var poll = // Some database query code.

    foreach (Question question in poll.Questions) {
        foreach (Answer answer in question.Answers) {
            database.Remove(answer);
        }

        // This is a sample line  that simulate an error.
        throw new Exception("deu pau"); 

        database.Remove(question);
    }

    database.Remove(poll);
}

该法典将数据库的分类处理方法按惯例启动,这一方法自动将交易投入数据库,但这使我的数据库处于一个前后不一的状况,因为答案被删除,但问题和投票不是。

在“处置”方法中,我可以发现,由于一种例外情况,而不是经常结束封闭区,因此我可以自动收回。

我不想人工添加一个试样......集束,我的目标是将整块用作合乎逻辑的安全交易经理,这样,如果执行是干净的,如果出现任何例外,那么它就会对数据库作出承诺。

你们是否对此有一些想法?

最佳回答

正如其他人所说的那样,你为此目的使用可支配的模式正是造成这些问题的原因。 如果模式不利于你,那么我就会改变模式。 通过实施使用区块的违约行为,你假定,数据库的每一使用都会导致承诺,显然不是这种情况,特别是如果发生错误。 明确承诺,可能与试捕/游击集团相结合,会更好。

然而,如果你真的想继续使用这一模式,你可以使用:

bool isInException = Marshal.GetExceptionPointers() != IntPtr.Zero
                        || Marshal.GetExceptionCode() != 0;

在你为确定是否有例外而实施的试运行中(详情请here)。

问题回答

所有其他人已经写下了你<代码>Database类别的正确设计,因此我不重复。 然而,我看不出为什么你想要做的事情是不可能的。 因此,情况就是如此。

你们想要做的是,在请打电话到<代码>Dispose时发现,这种方法是在例外情况下使用的。 当你能够做到这一点时,开发商必须明确打到<条码>。 然而,这里的问题是,在互联网上无法可靠地发现这一点。 虽然有机制对最后的推差(如HttpServerUtility.Get LastError),但这些机制是具体的东道国(即ASP)。 该网络还有一个作为窗口表格的机制。 虽然你可以写出具体东道国执行工作的文字,例如,只有执行项目才能完成。 NET还有另一个更为重要的问题:what,如果您的<代码>Database类别在例外情况下使用或创建?。 例如:

try
{
    // do something that might fail
}
catch (Exception ex)
{
    using (var database = new Database())
    {
        // Log the exception to the database
        database.Add(ex);
    } 
}

如上例,在<代码>Exception<>/code>类别中使用了/Database类别时,您的<代码>Dispose方法应当如何知道它仍必须实施? 我可以想办法解决这一问题,但这样做将非常脆弱,容易发生错误。 举一个例子。

在创建<代码>Database的过程中,你可以检查是否在例外情况下发出,如果情况如此,可以储存这一例外情况。 在请打电话到<代码>Dispose时,请检查最后提出的例外是否不同于附则的例外。 如果情况不同,你应退席。 如果没有,承诺。

虽然这似乎只是一种解决办法,但这一守则的例子是什么?

var logger = new Database();
try
{
    // do something that might fail
}
catch (Exception ex)
{
    logger.Add(ex);
    logger.Dispose();
}

例见<代码>Database。 因此,不能正确地发现它不会退缩。 虽然这可能是一个有争议的例子,但它表明,你在试图以无需明确要求<代码>Commit

归根结底,你会把“”类同起来难以设计,难以维持,你永远不会真正做到。

正如所有其他人已经说过的那样,需要一个明确的<代码>Commit或Complete电话的设计将更易于实施,更容易获得权利,易于维护,并使使用代码更加可读(例如,它考虑到开发商的期望)。

请注意,如果你再次担心开发商要把这一条码称作方法:你可以在<代码>Dispose的方法中做一些检查,看看它是否被称作没有Commit<>Commit,并写给该星,或在脱胎时设定一个断点。 采用这种解决办法仍然比试图完全删除

Update: Adrian wrote an intersting alternative to using HttpServerUtility.GetLastError. As Adrian notes, you can use Marshal.GetExceptionPointers() which is a generic way that would work on most hosts. Please note that this solution has the same drawbacks explained above and that calling the Marshal class is only possible in full trust

参看TransactionScope in System。 交易。 其方法要求你在交易范围上要求完成交易。 我将考虑设计你的数据库类别,以便遵循同样的模式:

using (var db = new Database()) 
{
   ... // Do some work
   db.Commit();
}

不过,你不妨在数据库之外引入交易概念。 如果消费者想要利用你的阶层,不希望利用交易,而且所有汽车都投入使用,会发生什么情况?

简言之,我认为不可能,BUT

你可以做的是,在你的旗帜上打上旗帜。 数据库级的违约值“false”(不太好)和最后一行,使用栏块,你称之为一种方法,将其“true”,然后在处置方法中,你可以核实国旗“具有例外”是否。

using (var db = new Database())
{
    // Do stuff

    db.Commit(); // Just set the flag to "true" (it s good to go)
}

数据库类别

public class Database
{
    // Your stuff

    private bool clean = false;

    public void Commit()
    {
        this.clean = true;
    }

    public void Dispose()
    {
        if (this.clean == true)
            CommitToDatabase();
        else
            Rollback();
    }
}

您应总结一下你在尝试/捕获物中使用块块的内容,并击退在捕获区的交易:

using (var database = new Database()) try
{
    var poll = // Some database query code.

    foreach (Question question in poll.Questions) {
        foreach (Answer answer in question.Answers) {
            database.Remove(answer);
        }

        // This is a sample line  that simulate an error.
        throw new Exception("deu pau"); 

        database.Remove(question);
    }

    database.Remove(poll);
}
catch( /*...Expected exception type here */ )
{
    database.Rollback();
}

如上文Anthony指出的,问题是你在这种情形下使用条款的错误。 可行的范式意在确保不管情景的结果如何,对物体资源进行清理(因此,一种例外、返回或造成使用块块的其他事件仍然引发处置方法)。 但是,你将这一目的重新定位为一种不同的意思,以进行交易。

我的建议将与其他人一样,采用与TransactionScope相同的模式。 交易结束时(在使用区块关闭之前)开发商必须明确指明交易是好的,并准备进行。 因此,如果一个例外情况导致执行,从而离开使用区块,那么在这种情况下,处置方法可以取代。 这仍然符合范式,因为退缩会是一种“清理”数据库标的的方法,以免它成为一个无效的国家。

这种设计上的转变也使你想做的工作更加容易,因为你赢得的就是要打仗。 NET试图尝试和“选择”例外。

你可以继承数据库类别,然后推翻处置方法(确保关闭 d资源),从而可以提出你可以加入的习俗。





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签