You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用方法后Struct值未改变?C#结构体AnimationCommand问题排查

结构体SetDuration方法修改值无效的问题解析

你定义了存储动画数据的AnimationCommand结构体,调用其SetDuration方法后,时长值始终未发生变化,相关代码如下:

结构体代码

public struct AnimationCommand
{
    float _duration;
    Action _onCompleteCallback;
    Action<float> _onUpdateCallback;

    public float Duration => _duration;

    public AnimationCommand(float animationTime, Action onComplete = null, Action<float> onUpdate = null)
    {
        _duration = animationTime;
        _onCompleteCallback = onComplete;
        _onUpdateCallback = onUpdate;
    }

    public void SetDuration(float animationTime) => _duration = animationTime;
}

子类调用代码

/*AnimationData是基类中的属性

[SerializeField]
AnimationCommand _animationData;
protected AnimationCommand AnimationData => _animationData;
*/

float delta = 10; //测试值
AnimationData.SetDuration(delta);
Debug.Log(delta + " :: " + AnimationData.Duration);

输出结果为10 :: 0,原因及解决方式如下:


问题核心:结构体的值类型特性 + 只读属性的拷贝行为

  1. 结构体是值类型:值类型的实例在赋值、传递或通过属性返回时,都会创建一个全新的拷贝,而非操作原实例。
  2. 只读属性的拷贝问题:你的AnimationData属性是表达式体只读属性(=> _animationData),每次访问AnimationData都会返回_animationData的一个新拷贝。
  3. 方法修改的是拷贝:调用AnimationData.SetDuration(delta)时,实际是在这个临时拷贝上修改_duration,原字段_animationData完全不受影响。后续再次访问AnimationData,又会返回一个基于原字段的新拷贝(初始值为0),所以日志输出不符合预期。

你的误解在于:调用结构体的方法无法避开值拷贝语义。结构体方法操作的是当前实例,但如果这个实例本身是一个拷贝(比如通过只读属性返回的),修改只会作用于拷贝,原实例不会变化。


解决方案

方案1:将结构体改为类(最直接)

类是引用类型,所有操作都针对同一个实例,不存在值拷贝问题,适合需要频繁修改内部状态的场景:

public class AnimationCommand
{
    // 其余代码逻辑保持不变
}

方案2:修改属性为可读写,替换整个结构体实例

修改基类的AnimationData属性为可读写:

protected AnimationCommand AnimationData
{
    get => _animationData;
    set => _animationData = value;
}

调用时先获取拷贝,修改后赋值回属性:

float delta = 10;
var tempAnimData = AnimationData;
tempAnimData.SetDuration(delta);
AnimationData = tempAnimData;
Debug.Log(delta + " :: " + AnimationData.Duration);

方案3:采用不可变结构体模式,返回新实例

修改SetDuration方法,返回一个修改后的新结构体实例:

public AnimationCommand SetDuration(float animationTime)
{
    return new AnimationCommand(animationTime, _onCompleteCallback, _onUpdateCallback);
}

调用时直接将返回的新实例赋值给属性:

float delta = 10;
AnimationData = AnimationData.SetDuration(delta);
Debug.Log(delta + " :: " + AnimationData.Duration);

内容的提问来源于stack exchange,提问作者WDUK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 20:13:06