Получение пути к файлу.cs, где был объявлен тип
Я работаю над процедурной системой генерации активов и хочу, чтобы она могла определять, изменился ли исходный файл конкретного актива, так что ему нужно только восстановить ресурсы, которые на самом деле будут другими.
Некоторый поиск в Google сказал мне, что нет никакого способа получить исходный файл типа, используя простое отражение, поэтому я пытаюсь найти обходной путь. Вот что я делаю:
- Получить список всех файлов.cs в каталоге проекта, используя Directory.GetFiles.
- Скомпилируйте каждый файл в его собственную сборку, используя CSharpCodeProvider.CompileAssemblyFromFile.
- Если существует compiledAssembly.GetType(targetType.FullName), то это исходный файл targetType.
Проблема в том, что шаг 2 дает ошибки компиляции без какого-либо описания:
- (0,0): ошибка:
- (0,0): ошибка: at (управляемая оболочка). System.Reflection.Assembly:GetTypes (bool)
- (0,0): ошибка: at (управляемая оболочка). System.Reflection.Assembly:GetTypes (bool)
- и т.п.
Я думаю, что это может быть из-за того, что текущая сборка или домен приложения или что-то уже содержит точный тип, который он пытается скомпилировать, но это только предположение. Кто-нибудь знает, что может быть причиной этих ошибок или как я могу их избежать?
Изменить: вот основной код для шага 2:
private static readonly CSharpCodeProvider CodeProvider = new CSharpCodeProvider();
private static readonly CompilerParameters CompilerOptions = new CompilerParameters();
static SourceInterpreter()
{
// We want a DLL in memory.
CompilerOptions.GenerateExecutable = false;
CompilerOptions.GenerateInMemory = true;
// Add references for UnityEngine and UnityEditor DLLs.
CompilerOptions.ReferencedAssemblies.Add(typeof(Application).Assembly.Location);
CompilerOptions.ReferencedAssemblies.Add(typeof(EditorApplication).Assembly.Location);
}
private static Assembly CompileCS(string filePath, out CompilerErrorCollection errors)
{
// Compile the assembly from the source script text.
CompilerResults result = CodeProvider.CompileAssemblyFromFile(CompilerOptions, filePath);
// Store any errors and warnings.
errors = result.Errors;
foreach (CompilerError e in errors)
{
if (!e.IsWarning) Debug.Log(e);
}
return result.CompiledAssembly;
}
1 ответ
Скрипты в единстве также рассматриваются как активы. Unity использует класс MonoScript для представления самого файла скрипта. Экземпляр класса MonoScript имеет метод GetClass для получения объекта System.Type для класса, который объявлен внутри этого файла сценария.
Класс MonoScript является производным от TextAsset, а также UnityEngine.Object. Загруженные экземпляры обычно можно найти с помощью Resources.FindObjectsOfTypeAll. Кроме того, есть два статических метода FromMonoBehaviour и FromScriptableObject, которые находят и возвращают правильный экземпляр MonoScript для данного экземпляра MonoBehaviour или ScriptableObject.
Если у вас есть экземпляр MonoScript, вы можете использовать GetAssetPath, чтобы определить, где хранится файл скрипта.
Я бы не советовал компилировать каждый класс вручную, поскольку, как вы уже упоминали, нельзя загружать один и тот же класс дважды из разных сборок, если они находятся в одном и том же пространстве имен.
К сожалению, в классе MonoScript нет метода FindFromType, поэтому вам нужно иметь экземпляр вашего класса или проверять каждый MonoScript в проекте вручную.