Unity中SpriteLibrary类编辑问题求助:自定义方法丢失且无法修改
问题描述
我对项目的运行机制和代码编译逻辑不太理解,不清楚当前问题的成因。我的代码需要从SpriteLibrary中获取数据,因为不知道正确的获取方式,我直接在SpriteLibrary类内部写了以下方法:
public void CopyLibraryFrom(SpriteLibrary sourceLibrary) { foreach (var sourceCategory in sourceLibrary.m_Library) { var targetCategory = new SpriteLibCategory { name = sourceCategory.name, categoryList = new List<SpriteCategoryEntry>() }; foreach (var sourceEntry in sourceCategory.categoryList) { var targetEntry = new SpriteCategoryEntry { name = sourceEntry.name, sprite = sourceEntry.sprite }; targetCategory.categoryList.Add(targetEntry); } m_Library.Add(targetCategory); } CacheOverrides(); RefreshSpriteResolvers(); }
遇到的问题:
- Visual Studio会自动删除我添加的这个方法和所有修改,得多次取消自动删除才能保存。我猜测是Unity自动更新
SpriteLibrary并重置为默认状态导致的。想问下能不能正常编辑保存SpriteLibrary?还是我的操作方式错了? - 一个月没打开Unity后,再次运行报错:"SpriteLibrary中不存在CopyLibraryFrom方法"。现在打开
SpriteLibrary显示是反编译的,完全没法编辑。我知道自己操作有误,但不知道正确做法是什么,该怎么修复当前问题?现在该怎么编辑它,或者有没有其他方法实现需求并正常运行?
解决方案
为什么不能直接编辑SpriteLibrary?
SpriteLibrary是Unity官方提供的内置类(属于Sprite Library Package或UI Toolkit模块),你看到的可编辑代码是Visual Studio自动生成的反编译元数据视图,直接修改这类内置类的代码完全不可行:
- Unity每次编译、刷新项目或重启时,都会重新加载官方编译好的程序集,你的修改会被自动覆盖,这就是Visual Studio自动删除代码的原因。
- 即使临时保存了修改,一旦Unity重新编译,内置程序集就会被还原,你的自定义方法会直接消失,导致后续报错。
正确实现方式:扩展方法
不要修改内置类,用C#的扩展方法实现需求,既不会破坏Unity内置代码,也能达到同样效果:
using UnityEngine; using System.Collections.Generic; using System.Reflection; // 根据你项目中SpriteLibrary的实际命名空间调整,比如UnityEngine.Experimental.U2D.Animation或UnityEngine.UIToolkit using UnityEngine.Experimental.U2D.Animation; public static class SpriteLibraryExtensions { public static void CopyLibraryFrom(this SpriteLibrary targetLibrary, SpriteLibrary sourceLibrary) { // 通过反射获取私有字段m_Library var libraryField = typeof(SpriteLibrary).GetField("m_Library", BindingFlags.NonPublic | BindingFlags.Instance); if (libraryField == null) return; var targetLibraryList = libraryField.GetValue(targetLibrary) as List<SpriteLibCategory>; var sourceLibraryList = libraryField.GetValue(sourceLibrary) as List<SpriteLibCategory>; if (targetLibraryList == null || sourceLibraryList == null) return; // 先清空目标库,避免重复添加 targetLibraryList.Clear(); foreach (var sourceCategory in sourceLibraryList) { var targetCategory = new SpriteLibCategory { name = sourceCategory.name, categoryList = new List<SpriteCategoryEntry>() }; foreach (var sourceEntry in sourceCategory.categoryList) { var targetEntry = new SpriteCategoryEntry { name = sourceEntry.name, sprite = sourceEntry.sprite }; targetCategory.categoryList.Add(targetEntry); } targetLibraryList.Add(targetCategory); } // 通过反射调用内置私有方法 var cacheOverridesMethod = typeof(SpriteLibrary).GetMethod("CacheOverrides", BindingFlags.NonPublic | BindingFlags.Instance); cacheOverridesMethod?.Invoke(targetLibrary, null); var refreshResolversMethod = typeof(SpriteLibrary).GetMethod("RefreshSpriteResolvers", BindingFlags.NonPublic | BindingFlags.Instance); refreshResolversMethod?.Invoke(targetLibrary, null); } }
使用方式
在业务代码中直接像调用内置方法一样使用:
SpriteLibrary targetLib = GetComponent<SpriteLibrary>(); SpriteLibrary sourceLib = ...; // 获取源SpriteLibrary实例 targetLib.CopyLibraryFrom(sourceLib);
修复当前报错的步骤
- 彻底删除之前对
SpriteLibrary内置类的所有修改,确保Unity内置程序集未被篡改。 - 创建上述
SpriteLibraryExtensions类,放在项目Assets目录下的任意脚本文件夹中。 - 重启Unity和Visual Studio,让项目重新编译。
- 将原来调用
CopyLibraryFrom的代码改为使用扩展方法的形式,即可解决报错。
额外注意事项
- 如果
SpriteLibCategory或SpriteCategoryEntry是Unity内部类无法直接实例化,可以改用反射复制字段值。 - 务必确认
SpriteLibrary的正确命名空间,不同Unity版本的命名空间可能不同,需根据项目实际情况调整。
内容的提问来源于stack exchange,提问作者Дмитрий Титов
相关产品推荐
相关产品推荐

