我正试着go 理解我所看到的这种行为.我知道 struct 在移动时会被复制,因为它们是ValueType.但是我不明白为什么这个示例代码会失败.这里只有一个简单的C#代码来演示这个问题:

public class MyClass
    {
        private MyStruct ms;

        public MyClass()
        {
            ms = new MyStruct("");
        }

        public void Add(dynamic d)
        {
            ms.Add(d);
        }

        public void Print()
        {
            Console.WriteLine("L: " + ms.GetLength());
        }
    }

    public struct MyStruct
    {
        private dynamic[] items;

        public MyStruct(string junk)
        {
            items = new dynamic[0];
        }

        public int GetLength()
        {
            return items.Length;
        }

        public void Add(dynamic d)
        {
            Array.Resize<dynamic>(ref items, items.Length + 1);
            items[items.Length - 1] = d;
        }
    }

通过运行下面的代码,我得到了错误的结果.在调试器中,我可以看到项已添加,但并不持久,这意味着我看到了两次"L:0"(而不是"L:0"和"L:1"):

MyClass mc = new MyClass();
mc.Print();
mc.Add("Test");
mc.Print();

我注意到,如果在MyClass.Add中调用ms.Add时使用的类型不是"动态"(例如,"字符串"),则可以很好地工作.大概是这样的:

public void Add(string d)
{
   ms.Add(d);
}

或者甚至是这样:

public void Add(dynamic d)
{
   string s = d.ToString();
   ms.Add(s);
}

这让我认为我可能正在制作一份副本,但如果是这样的话,我不明白为什么.我正在直接访问该字段,因此我预计这种情况不会发生.

非常提前感谢您.

推荐答案

任何类型为dynamic的操作(包括带有dynamic参数的调用)都使用运行时绑定,因此最终会使用反射--正如@AlexeiLevenkov在他的 comments 中指出的那样,这涉及装箱.

您可以通过添加重载来证明这一点

public void Add(string d)
{
    Console.WriteLine("Add(String)");
    Array.Resize<dynamic>(ref items, items.Length + 1);
    items[items.Length - 1] = d;
}

MyStruct.这将产生输出

L: 0 
AddString 
L: 0

如果您查看一下生成的IL,这包括:

ldfld   MyClass.ms
ldarg.1 
callvirt    Action <CallSite, MyStruct, Object>.Invoke (CallSite, MyStruct, Object)

因此,该 struct 将作为参数传递给Action,最终执行对动态确定的重载ms.Add的调用.此参数传递是创建副本的位置.

Csharp相关问答推荐

VB.Net的SON模式导致集合代码不工作

将实例绑定方法传递到列表foreach

使用ElasticsearchClient设置忽略属性.默认MappingFor<>

利用.NET 8中的AddStandardResilienceDeliveries和AddStandardHedgingDeliveries实现Resiliency

ß != ss与ICU进行不区分大小写的比较

如何删除文件的基础上嵌入的时间戳嵌入文件名

需要在重新启动ApplicartionPool或IIS后启动/唤醒API的帮助

查找表中的模式

ASP.NET Core AutoMapper:如何解决错误 CS0121调用在以下方法或属性之间不明确

在具有不同属性名称的两个类之间创建关系

如何捕获对ASP.NET核心应用程序的所有请求并将其发送到一个页面

在C#中,将两个哈希集连接在一起的时间复杂度是多少?

如何通过寻找向量长度来优化两个循环?

VS 2022 for ASP.NET Core中缺少自定义项模板

Postgres ENUM类型在第一次运行时对Dapper不可见

.NET8->;并发词典总是比普通词典快...怎么回事?[包含基准结果和代码]

如何在一次数据库调用中为ASP.NET核心身份用户加载角色

c#在后台实现类型化数组

如何在.NET MAUI上在iOS和Mac之间共享代码?(no条件编译和无代码重复)

使用本地公共PEM文件加密字符串,使用Azure KayVault中的私钥解密