gpt4 book ai didi

c# - 如果底层实现是结构,接口(interface)类型的变量是否充当值类型?

转载 作者:行者123 更新时间:2023-11-30 14:58:58 27 4
gpt4 key购买 nike

我在看 this问题,除了枚举某些东西的一种相当奇怪的方式之外,操作遇到了麻烦,因为枚举器是一个结构。我知道返回或传递一个结构使用一个副本,因为它是一个值类型:

public MyStruct GetThingButActuallyJustCopyOfIt() 
{
return this.myStructField;
}

public void PretendToDoSomething(MyStruct thingy) 
{
thingy.desc = "this doesn't work as expected";
}

所以我的问题是,如果 MyStruct 实现了 IMyInterface(例如 IEnumerable),这些类型的方法是否会按预期工作?

public struct MyStruct : IMyInterface { ... }

//will caller be able to modify the property of the returned IMyInterface?
public IMyInterface ActuallyStruct() { return (IMyInterface)this.myStruct; }

//will the interface you pass in get its value changed?
public void SetInterfaceProp(IMyInterface thingy)
{
thingy.desc = "the implementing type is a struct";
}

最佳答案

是的,该代码可以工作,但需要解释一下,因为整个世界的代码都无法工作,除非您知道这一点,否则您很可能会陷入其中。

在我忘记之前:Mutable structs are evil .好的,让我们继续前进。

举个简单的例子,可以用LINQPad验证此代码:

void Main()
{
var s = new MyStruct();
Test(s);
Debug.WriteLine(s.Description);
}

public void Test(IMyInterface i)
{
i.Description = "Test";
}

public interface IMyInterface
{
string Description { get; set; }
}

public struct MyStruct : IMyInterface
{
public string Description { get; set; }
}

执行时,会打印什么?

null

好的,为什么?

嗯,问题是这一行:

Test(s);

这实际上将构造该结构并将装箱的副本传递给该方法。您已成功修改盒装副本,但未修改原始 s 变量,该变量从未分配任何内容,因此仍为 null

好的,所以如果我们只更改第一段代码中的一行:

IMyInterface s = new MyStruct();

这会改变结果吗?

是的,因为现在您要在此处装箱该结构,并且始终使用装箱的副本。在这个上下文中,它的行为就像一个对象,您正在修改盒装副本并写出盒装副本的内容。

因此,每当您对该结构进行装箱或拆箱时,问题就会出现,然后您会得到独立生活的副本。

结论:可变结构是邪恶的。

我现在在这里看到两个关于使用 ref 的答案,这是找错了树。使用 ref 意味着您在添加 ref 之前已经解决了问题。

这是一个例子。

如果我们将上面的 Test 方法更改为采用 ref 参数:

public void Test(ref IMyInterface i)

这会改变什么吗?

否,因为此代码现在无效:

var s = new MyStruct();
Test(ref s);

你会得到这个:

The best overloaded method match for 'UserQuery.Test(ref UserQuery.IMyInterface)' has some invalid arguments

Argument 1: cannot convert from 'ref UserQuery.MyStruct' to 'ref UserQuery.IMyInterface'

因此您将代码更改为:

IMyInterface s = new MyStruct();
Test(ref s);

但现在您回到了我的示例,只是添加了 ref,我展示了它对于传播回更改不是必需的。

所以使用 ref 是正交的,它解决了不同的问题,但不是这个。

好的,关于 ref 的更多评论。

是的,当然使用 ref 传递一个结构确实会使更改在整个程序中流动。

这不是这个问题的意思。问题贴了一些代码,问能不能用,能用。 在这个特殊的代码变体中它会起作用。但是很容易绊倒。并特别注意问题是关于结构和接口(interface)的。如果您将接口(interface)排除在外,并使用 ref 传递结构,那么您有什么? 一个不同的问题

添加 ref 不会改变这个问题,也不会改变答案。

关于c# - 如果底层实现是结构,接口(interface)类型的变量是否充当值类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17701547/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com