结构体和 IDisposable

发布于 2024-12-12 07:43:26 字数 957 浏览 0 评论 0原文

我想知道为什么它不能编译?

public static void Main(string[] args)
{
    using (MyStruct sss = new MyStruct())
    {

        sss.s = "fsdfd";// Cannot modify members of 'sss' because it is a 'using variable' 

        //sss.Set(12);    //but it's ok
    }
}

public struct MyStruct : IDisposable
{
    public int n;
    public string s;

    public void Set(int n)
    {
        this.n = n;
    }
    public void Dispose()
    {
        Console.WriteLine("dispose");
    }
}

更新: 但效果很完美。为什么?

public static void Main(string[] args)
        {

            using (MyClass sss = new MyClass())
            {
                sss.Field = "fsdfd"; 
            }


        }

public class MyClass:IDisposable {

    public string Property1 { get; set; }
    public string Field;
    public void Method1 (){}

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

I wonder why does it not compile?

public static void Main(string[] args)
{
    using (MyStruct sss = new MyStruct())
    {

        sss.s = "fsdfd";// Cannot modify members of 'sss' because it is a 'using variable' 

        //sss.Set(12);    //but it's ok
    }
}

public struct MyStruct : IDisposable
{
    public int n;
    public string s;

    public void Set(int n)
    {
        this.n = n;
    }
    public void Dispose()
    {
        Console.WriteLine("dispose");
    }
}

UPDATE:
But it works perfect. Why?

public static void Main(string[] args)
        {

            using (MyClass sss = new MyClass())
            {
                sss.Field = "fsdfd"; 
            }


        }

public class MyClass:IDisposable {

    public string Property1 { get; set; }
    public string Field;
    public void Method1 (){}

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

场罚期间 2024-12-19 07:43:26

很多人都链接到了我关于改变值类型以及为什么这是一个坏主意的文章。尽管在理解为什么处理结构是一个坏主意以及在这样做时改变结构是一个更糟糕的主意时理解这些概念很重要,但这实际上并不是链接到的正确文章。您想阅读的那本以令人难以忍受的细节解释了这一切的文章是:

http://ericlippert.com/2011/03/14/to-box-or-not-to-box/

简而言之:“使用”制作副本价值类型,因此您将处置副本。这意味着您必须非常小心 - 如果该值是操作系统句柄,则内存中可能存在该值的大量副本,并且您需要确保无论如何都将其一次性处理掉有多少份。

另请参阅 如果我的结构实现了 IDisposable,在 using 语句中使用时它会被装箱吗?

A number of people have linked to my article about mutating value types and why it is a bad idea. Though it is important to understand those concepts when understanding why its a bad idea to dispose a struct, and a worse idea to mutate the struct when you do, that is not actually the right article to link to. The one you want to read that explains all this in excruciating detail is:

http://ericlippert.com/2011/03/14/to-box-or-not-to-box/

In short: "using" makes a copy of the value type, and you are therefore disposing a copy. That means you have to be very careful -- if the value is, say, an OS handle, there might be lots of copies of that value lying around memory, and you'll need to make sure that you dispose it exactly once no matter how many copies there are.

See also If my struct implements IDisposable will it be boxed when used in a using statement?

空‖城人不在 2024-12-19 07:43:26

类和结构场景实际上是相同的,但您会看到不同的效果。

当您将类示例更改为:时,

using (MyClass sss = new MyClass())
{
    sss = null;          // the same error
    sss.Field = "fsdfd"; // ok
}

您将在第一个作业中遇到相同的错误。

解释是:您无法更改(变异)using-variable。但对于适用于引用而不是实例的类。

教训是:不要使用结构。特别是不要使用可变结构。

The class and struct scenarios are actually the same but you see different effects.

When you change the class example to :

using (MyClass sss = new MyClass())
{
    sss = null;          // the same error
    sss.Field = "fsdfd"; // ok
}

You will get the same error on the first assignment.

The explanation is: You cannot change (mutate) the using-variable. But for a class that applies to the reference, not to the instance.

And the lesson is: Don't use structs. And especially don't use mutable structs.

笑看君怀她人 2024-12-19 07:43:26

using 语句的想法是确保在离开块时释放资源。

当您分配给结构变量时,您实际上是将其替换为该类型的全新对象。因此,在这种情况下,您将摆脱掉本应被处置的对象。

The idea of a using statement is to ensure that a resource is disposed of when you leave the block.

When you assign to a struct variable, you are effectively replacing it with a completely new object of that type. So in this context you would have got rid of the object that was supposedly going to be disposed of.

情独悲 2024-12-19 07:43:26

考虑以下事项:

 interface IFoo: IDisposable { int Bar {get;set;}}

 struct Foo : IFoo
 {
   public int Bar { get; set; }
   public void Dispose() 
   {
     Console.WriteLine("Disposed: {0}", Bar);
   }
 }

现在执行:

  IFoo f = new Foo();

  using (f)
  {
    f.Bar = 42;
  }

  Console.WriteLine(f.Bar); 

打印:

Disposed: 42
42

Consider the following:

 interface IFoo: IDisposable { int Bar {get;set;}}

 struct Foo : IFoo
 {
   public int Bar { get; set; }
   public void Dispose() 
   {
     Console.WriteLine("Disposed: {0}", Bar);
   }
 }

Now do:

  IFoo f = new Foo();

  using (f)
  {
    f.Bar = 42;
  }

  Console.WriteLine(f.Bar); 

This prints:

Disposed: 42
42
宛菡 2024-12-19 07:43:26

最后我理解了它:-)我将发表我的观点:-):-)

现在...

using (MyType something = new MyType())

readonly元等效,

using (readonly MyType something = new MyType())

具有与readonly相同的含义类/结构声明中的 code> 关键字。

如果 MyType 是引用,则该引用(而不是被引用的对象)受到“保护”。所以你不能这样做:

using (readonly MyType something = new MyType())
    something = null;

但你可以

    something.somethingelse = 0;

在 using 块中。

如果MyType是值类型,则readonly“修饰符”扩展到其字段/属性。因此,他们没有在 using 中引入一种新类型的“const-ness/readonly-ness”,他们只是使用了现有的类型。

所以问题应该是:为什么我不能修改只读值类型的字段/属性?

请注意,如果您这样做:

public void Dispose()
{
    Console.WriteLine("During dispose: {0}", n);
}

var sss = new MyStruct();

using (sss)
{
    sss.n = 12;
    Console.WriteLine("In using: {0}", sss.n); // 12
}

Console.WriteLine("Outside using: {0}", sss.n); // 12

结果

In using: 12
During dispose: 0
Outside using: 12

using 正在执行 sss 的“私有”副本,并且 sss.n = 12 正在访问“原始”sss,而 Dispose 正在访问副本。

Finally I have comprehended it :-) I'll post my view :-) :-)

Now...

using (MyType something = new MyType())

is meta-equivalent to

using (readonly MyType something = new MyType())

with readonly having the same meaning of the readonly keyword in class/struct declaration.

If MyType is a reference, then it is the reference (and not the referenced object) that is "protected". So you can't do:

using (readonly MyType something = new MyType())
    something = null;

but you can

    something.somethingelse = 0;

in the using block.

If MyType is a value type, the readonly "modifier" extends to its fields/properties. So they didn't introduced a new type of "const-ness/readonly-ness" in using, they simply used the one they had.

So the question should be: why can't I modify fields/properties of readonly value types?

Note that if you do this:

public void Dispose()
{
    Console.WriteLine("During dispose: {0}", n);
}

var sss = new MyStruct();

using (sss)
{
    sss.n = 12;
    Console.WriteLine("In using: {0}", sss.n); // 12
}

Console.WriteLine("Outside using: {0}", sss.n); // 12

Result

In using: 12
During dispose: 0
Outside using: 12

so the using is doing a "private" copy of sss, and sss.n = 12 is accessing the "original" sss, while Dispose is accessing the copy.

一袭水袖舞倾城 2024-12-19 07:43:26

在 using 块中,对象是只读的,不能修改或重新分配。

检查此链接:http://msdn.microsoft.com/en-us/library /yh598w02.aspx

Within the using block, the object is read-only and cannot be modified or reassigned.

check this link: http://msdn.microsoft.com/en-us/library/yh598w02.aspx

慢慢从新开始 2024-12-19 07:43:26

我对此不是100%确定,所以如果我错了,请大家纠正我。

在这种情况下,编译器允许您修改类的字段(而不是结构体)的原因与内存管理有关。对于类(即引用类型),不是对象,而是引用本身才是值。因此,当您修改该对象中的字段时,您不是在操作该值,而是在其他位置操作由该值引用的内存块。对于结构体来说,对象就是值,因此当您操作结构体中的字段时,您实际上正在操作此时被视为只读的值。

编译器允许方法调用(进而修改字段)的原因很简单,它无法进行足够深入的分析来确定该方法是否执行此类修改。

MS Connect 上有一个关于此问题的(已关闭)案例,可能会提供更多信息:无法使用 IDisposable 分配给结构体字段,并且当它是一个 using 变量 - CS1654 错误

I am not 100% sure on this, so anyone please correct me if I'm wrong.

The reason that the compiler allows you to modify fields of a class in this scenario, but not a struct, is related to memory management. In the case of a class (i.e a reference type), the not the object, but the reference itself is the value. So when you modify a field in that object, you are not manipulating the value, but a memory block somewhere else, referenced by the value. In the the case of a struct, the object is the value, so when you manipulate a field in the struct, you are in fact manipulating the value that is considered read-only at this time.

The reason the compiler will allow the method call (that in turn modifies a field) is simply that it cannot analyze deeply enough to determine whether the method performs such modification or not.

There is a (closed) case at MS Connect regarding this, that may shed some more light: Cannot assign to field of struct with IDisposable and when it is a using variable - CS1654 error

夏雨凉 2024-12-19 07:43:26

该结构被标记为只读。您试图修改一个公共成员变量,编译器将其标记为只读,因此禁止修改。

但是,允许调用 Set(),因为编译器无法知道该调用会改变结构的状态。实际上,这是一种改变只读值的巧妙方法!

有关详细信息,请参阅 Eric Lippert 的改变只读结构的帖子。

The struct is flagged as read-only. You're trying to modify a public member variable, which the compiler flags as read-only and so prohibits.

However, the call to Set() is allowed because the compiler has no way of knowing the the call will mutate the state of the struct. It is, in effect, a crafty way of mutating a readonly value!

Take a look at Eric Lippert's post of mutating readonly structs for more info.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文