Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我可以安全地在using语句中使用对象初始值设定项吗?_C#_Using Statement_Object Initializers - Fatal编程技术网

C# 我可以安全地在using语句中使用对象初始值设定项吗?

C# 我可以安全地在using语句中使用对象初始值设定项吗?,c#,using-statement,object-initializers,C#,Using Statement,Object Initializers,我想知道的是,使用是否会以某种方式阻止正确处理它们内部声明的资源,例如 using (Disposable resource = new Disposable() { Property = property }) { // ... } 我已经了解到,对象初始值设定项只是synctatic sugar,编译器将其转换为类似于以下代码的内容: MyClass tmp = new MyClass(); tmp.Property1 = 1; tmp.Property2 = 2; actualO

我想知道的是,使用是否会以某种方式阻止正确处理它们内部声明的资源,例如

using (Disposable resource = new Disposable() { Property = property })
{
   // ...
}
我已经了解到,对象初始值设定项只是synctatic sugar,编译器将其转换为类似于以下代码的内容:

MyClass tmp = new MyClass(); 
tmp.Property1 = 1;
tmp.Property2 = 2;
actualObjectYouWantToInitialize = tmp;
即使我看起来像一个糊涂的无知者,我还是想要求澄清。初始化对象(据我所知)是指向另一个对象的指针(据我所知,也是指针)这一事实是否会干扰
使用
语句对资源的处理?

主要(仅)危险在于,如果设置
属性
失败(即引发异常),然后
资源

通常情况下,
using
块中的异常是可以处理的,因为
using
try的语法糖。。最后

这里的问题是,当
Property=Property
执行时,您还没有使用
块“进入”
。这与构造函数抛出异常时发生的情况基本相同

最后
块将尝试
处理
的是
资源
——但是
资源
从未设置过——
资源
(如
actualObjectYouWantToInitialize
示例所示)已设置

展示了这在实践中是如何发生的。请注意,
Dispose
只记录了一次,即使有两个
使用

using System;

namespace Bob
{
    public class Disposable : IDisposable
    {
        private int _property;

        public int Property { get => _property; set => throw new Exception(); }

        public void Dispose()
        {
            Console.WriteLine("Disposed");
        }
    }

    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("1");
            using (var resource = new Disposable())
            {
                Console.WriteLine("2");
            }
            Console.WriteLine("3");


            using (var resource = new Disposable() { Property = 1 })
            {
                Console.WriteLine("4");

            }
            Console.WriteLine("5");
        }
    }
}

可能有助于检测此问题。

@mjwills的答案是正确的。详情如下:

public void M()
{
    using (var x = new Test{Property = ""})
    {

    }
}
将生成以下IL代码:

.method public hidebysig 
    instance void M () cil managed 
{
    // Method begins at RVA 0x206c
    // Code size 35 (0x23)
    .maxstack 3
    .locals init (
        [0] class Test
    )

    IL_0000: nop
    IL_0001: newobj instance void Test::.ctor()
    IL_0006: dup
    IL_0007: ldstr ""
    IL_000c: callvirt instance void Test::set_Property(string)
    IL_0011: nop
    IL_0012: stloc.0
    .try
    {
        IL_0013: nop
        IL_0014: nop
        IL_0015: leave.s IL_0022
    } // end .try
    finally
    {
        // sequence point: hidden
        IL_0017: ldloc.0
        IL_0018: brfalse.s IL_0021

        IL_001a: ldloc.0
        IL_001b: callvirt instance void [mscorlib]System.IDisposable::Dispose()
        IL_0020: nop

        // sequence point: hidden
        IL_0021: endfinally
    } // end handler

    IL_0022: ret
} // end of method Test::M

您可以看到在进入try之前调用了属性setter,这将导致在setter中出现异常时最终无法调用。

@TimSchmelter我刚刚用以下类测试了这一点:
public class Test:IDisposable{public string property{get=>“Hello”;set=>throw new exception();}public void Dispose(){Console.WriteLine(“Disposed”);}}
。当运行
using(var x=new Test(){Property=“Test”})
@JonathonChase时没有调用Dispose,我认为这是因为编译器使用
转换为
try finally
在调用
Dispose()
之前检查资源是否为
null
,初始化失败时就是这种情况。@StackLloyd许多人都设置了
资源
变量的心智模型,然后在其上设置了属性(这是错误的)。这种心理模型可能就是一些人认为对象将被处理的原因。@StackLloyd通过使用对象初始值设定项语法,首先创建对象,然后设置属性。因此创建了实例(需要处理),但没有(如您所说)分配给将在finally块中处理的变量。“那么你有漏洞了。”勒内·沃格特明白了。那太丢脸了。。。总的来说,这意味着内部使用语句的对象初始值设定项应该被视为不好的做法。@StackLloyd我不确定我会称之为不光彩。这是两个句法特征如何相交的副作用(或结果)。如果你仔细想想,它是非常有意义的(我的意思是它可能不是你想要的——但是考虑到这两个特性是如何独立工作的,它们一起玩的方式是有意义的)。此外,在实践中,这很少是一个问题。大多数属性设置程序不会抛出异常。@mjwills虽然这是完全正确的,但我认为应该以某种方式警告C#程序员此类交互,因为它们几乎从来都不是问题,直到它们不知不觉地成为问题。在这里发布之前,我在官方文件上搜索了答案,但没有结果。
.method public hidebysig 
    instance void M () cil managed 
{
    // Method begins at RVA 0x206c
    // Code size 35 (0x23)
    .maxstack 3
    .locals init (
        [0] class Test
    )

    IL_0000: nop
    IL_0001: newobj instance void Test::.ctor()
    IL_0006: dup
    IL_0007: ldstr ""
    IL_000c: callvirt instance void Test::set_Property(string)
    IL_0011: nop
    IL_0012: stloc.0
    .try
    {
        IL_0013: nop
        IL_0014: nop
        IL_0015: leave.s IL_0022
    } // end .try
    finally
    {
        // sequence point: hidden
        IL_0017: ldloc.0
        IL_0018: brfalse.s IL_0021

        IL_001a: ldloc.0
        IL_001b: callvirt instance void [mscorlib]System.IDisposable::Dispose()
        IL_0020: nop

        // sequence point: hidden
        IL_0021: endfinally
    } // end handler

    IL_0022: ret
} // end of method Test::M