diff --git a/SpineViewer/Dialogs/BatchOpenSpineDialog.cs b/SpineViewer/Dialogs/BatchOpenSpineDialog.cs
index 70bf944..5e753eb 100644
--- a/SpineViewer/Dialogs/BatchOpenSpineDialog.cs
+++ b/SpineViewer/Dialogs/BatchOpenSpineDialog.cs
@@ -48,7 +48,7 @@ namespace SpineViewer.Dialogs
}
}
- if (version != Spine.Version.Auto && !Spine.Spine.ImplementedVersions.Contains(version))
+ if (version != Spine.Version.Auto && !Spine.Spine.HasImplementation(version))
{
MessageBox.Info($"{version.GetName()} 版本尚未实现(咕咕咕~)");
return;
diff --git a/SpineViewer/Dialogs/ConvertFileFormatDialog.cs b/SpineViewer/Dialogs/ConvertFileFormatDialog.cs
index 67ec272..a3363cb 100644
--- a/SpineViewer/Dialogs/ConvertFileFormatDialog.cs
+++ b/SpineViewer/Dialogs/ConvertFileFormatDialog.cs
@@ -59,13 +59,13 @@ namespace SpineViewer.Dialogs
}
}
- if (sourceVersion != Spine.Version.Auto && !SkeletonConverter.ImplementedVersions.Contains(sourceVersion))
+ if (sourceVersion != Spine.Version.Auto && !SkeletonConverter.HasImplementation(sourceVersion))
{
MessageBox.Info($"{sourceVersion.GetName()} 版本尚未实现(咕咕咕~)");
return;
}
- if (!SkeletonConverter.ImplementedVersions.Contains(targetVersion))
+ if (!SkeletonConverter.HasImplementation(targetVersion))
{
MessageBox.Info($"{targetVersion.GetName()} 版本尚未实现(咕咕咕~)");
return;
diff --git a/SpineViewer/Dialogs/OpenSpineDialog.cs b/SpineViewer/Dialogs/OpenSpineDialog.cs
index e754998..d270855 100644
--- a/SpineViewer/Dialogs/OpenSpineDialog.cs
+++ b/SpineViewer/Dialogs/OpenSpineDialog.cs
@@ -79,7 +79,7 @@ namespace SpineViewer.Dialogs
atlasPath = Path.GetFullPath(atlasPath);
}
- if (version != Spine.Version.Auto && !Spine.Spine.ImplementedVersions.Contains(version))
+ if (version != Spine.Version.Auto && !Spine.Spine.HasImplementation(version))
{
MessageBox.Info($"{version.GetName()} 版本尚未实现(咕咕咕~)");
return;
diff --git a/SpineViewer/Exporter/ExportArgs.cs b/SpineViewer/Exporter/ExportArgs.cs
index 077d41e..c0ba23b 100644
--- a/SpineViewer/Exporter/ExportArgs.cs
+++ b/SpineViewer/Exporter/ExportArgs.cs
@@ -14,40 +14,18 @@ namespace SpineViewer.Exporter
///
/// 导出参数基类
///
- public abstract class ExportArgs
+ public abstract class ExportArgs : ImplementationResolver
{
- ///
- /// 实现类缓存
- ///
- private static readonly Dictionary ImplementationTypes = [];
-
- static ExportArgs()
- {
- var impTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(ExportArgs).IsAssignableFrom(t) && !t.IsAbstract);
- foreach (var type in impTypes)
- {
- var attr = type.GetCustomAttribute();
- if (attr is not null)
- {
- if (ImplementationTypes.ContainsKey(attr.ExportType))
- throw new InvalidOperationException($"Multiple implementations found: {attr.ExportType}");
- ImplementationTypes[attr.ExportType] = type;
- }
- }
- Program.Logger.Debug("Find export args implementations: [{}]", string.Join(", ", ImplementationTypes.Keys));
- }
-
///
/// 创建指定类型导出参数
///
+ /// 导出类型
+ /// 分辨率
+ /// 导出视图
+ /// 仅渲染选中
+ /// 返回与指定 匹配的导出参数实例
public static ExportArgs New(ExportType exportType, Size resolution, SFML.Graphics.View view, bool renderSelectedOnly)
- {
- if (!ImplementationTypes.TryGetValue(exportType, out var type))
- {
- throw new NotImplementedException($"Not implemented type: {exportType}");
- }
- return (ExportArgs)Activator.CreateInstance(type, resolution, view, renderSelectedOnly);
- }
+ => New(exportType, resolution, view, renderSelectedOnly);
public ExportArgs(Size resolution, SFML.Graphics.View view, bool renderSelectedOnly)
{
diff --git a/SpineViewer/Exporter/ExportHelper.cs b/SpineViewer/Exporter/ExportHelper.cs
index c75fa49..ec889e3 100644
--- a/SpineViewer/Exporter/ExportHelper.cs
+++ b/SpineViewer/Exporter/ExportHelper.cs
@@ -26,14 +26,9 @@ namespace SpineViewer.Exporter
/// 导出实现类标记
///
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
- public class ExportImplementationAttribute : Attribute
+ public class ExportImplementationAttribute(ExportType exportType) : Attribute, IImplementationKey
{
- public ExportType ExportType { get; }
-
- public ExportImplementationAttribute(ExportType exportType)
- {
- ExportType = exportType;
- }
+ public ExportType ImplementationKey { get; private set; } = exportType;
}
///
diff --git a/SpineViewer/Exporter/Exporter.cs b/SpineViewer/Exporter/Exporter.cs
index 018ea65..298e420 100644
--- a/SpineViewer/Exporter/Exporter.cs
+++ b/SpineViewer/Exporter/Exporter.cs
@@ -12,56 +12,25 @@ namespace SpineViewer.Exporter
///
/// 导出器基类
///
- public abstract class Exporter
+ public abstract class Exporter(ExportArgs exportArgs) : ImplementationResolver
{
///
- /// 实现类缓存
+ /// 创建指定类型导出器
///
- private static readonly Dictionary ImplementationTypes = [];
-
- static Exporter()
- {
- var impTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(Exporter).IsAssignableFrom(t) && !t.IsAbstract);
- foreach (var type in impTypes)
- {
- var attr = type.GetCustomAttribute();
- if (attr is not null)
- {
- if (ImplementationTypes.ContainsKey(attr.ExportType))
- throw new InvalidOperationException($"Multiple implementations found: {attr.ExportType}");
- ImplementationTypes[attr.ExportType] = type;
- }
- }
- Program.Logger.Debug("Find exporter implementations: [{}]", string.Join(", ", ImplementationTypes.Keys));
- }
-
- ///
- /// 创建指定类型导出参数
- ///
- public static Exporter New(ExportType exportType, ExportArgs exportArgs)
- {
- if (!ImplementationTypes.TryGetValue(exportType, out var type))
- {
- throw new NotImplementedException($"Not implemented type: {exportType}");
- }
- return (Exporter)Activator.CreateInstance(type, exportArgs);
- }
+ /// 导出类型
+ /// 与 匹配的导出参数
+ /// 与 匹配的导出器
+ public static Exporter New(ExportType exportType, ExportArgs exportArgs) => New(exportType, exportArgs);
///
/// 导出参数
///
- public ExportArgs ExportArgs { get; }
+ public ExportArgs ExportArgs { get; } = exportArgs;
///
/// 可用于文件名的时间戳字符串
///
- protected readonly string timestamp;
-
- public Exporter(ExportArgs exportArgs)
- {
- ExportArgs = exportArgs;
- timestamp = DateTime.Now.ToString("yyMMddHHmmss");
- }
+ protected readonly string timestamp = DateTime.Now.ToString("yyMMddHHmmss");
///
/// 获取供渲染的 SFML.Graphics.RenderTexture
diff --git a/SpineViewer/ImplementationResolver.cs b/SpineViewer/ImplementationResolver.cs
new file mode 100644
index 0000000..bb2f23e
--- /dev/null
+++ b/SpineViewer/ImplementationResolver.cs
@@ -0,0 +1,67 @@
+using SpineViewer.Exporter;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using static SFML.Window.Keyboard;
+
+namespace SpineViewer
+{
+ public interface IImplementationKey
+ {
+ TKey ImplementationKey { get; }
+ }
+
+ ///
+ /// 可以使用反射查找基类关联的所有实现类
+ ///
+ /// 所有实现类的基类型
+ /// 实现类类型属性标记类型
+ /// /// 实现类类型标记类型
+ public abstract class ImplementationResolver where TAttr : Attribute, IImplementationKey
+ {
+ ///
+ /// 实现类型缓存
+ ///
+ private static readonly Dictionary ImplementationTypes = new();
+
+ static ImplementationResolver()
+ {
+ var baseType = typeof(TBase);
+ var impTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => baseType.IsAssignableFrom(t) && !t.IsAbstract);
+ foreach (var type in impTypes)
+ {
+ var attr = type.GetCustomAttribute();
+ if (attr is not null)
+ {
+ var key = attr.ImplementationKey;
+ if (ImplementationTypes.ContainsKey(key))
+ throw new InvalidOperationException($"Multiple implementations found for key: {key}");
+ ImplementationTypes[key] = type;
+ }
+ }
+ Program.Logger.Debug("Found implementations for {}: {}", baseType, string.Join(", ", ImplementationTypes.Keys));
+ }
+
+ ///
+ /// 判断某种类型是否实现
+ ///
+ public static bool HasImplementation(TKey key) => ImplementationTypes.ContainsKey(key);
+
+ ///
+ /// 根据实现类键和参数创建实例
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected static TBase New(TKey impKey, params object?[]? args)
+ {
+ if (!ImplementationTypes.TryGetValue(impKey, out var type))
+ throw new NotImplementedException($"Not implemented type for {typeof(TBase)}: {impKey}");
+ return (TBase)Activator.CreateInstance(type, args);
+ }
+ }
+}
diff --git a/SpineViewer/Spine/SkeletonConverter.cs b/SpineViewer/Spine/SkeletonConverter.cs
index b675e3d..b3faf57 100644
--- a/SpineViewer/Spine/SkeletonConverter.cs
+++ b/SpineViewer/Spine/SkeletonConverter.cs
@@ -15,46 +15,12 @@ namespace SpineViewer.Spine
///
/// SkeletonConverter 基类, 使用静态方法 New 来创建具体版本对象
///
- public abstract class SkeletonConverter
+ public abstract class SkeletonConverter : ImplementationResolver
{
- ///
- /// 实现类缓存
- ///
- private static readonly Dictionary ImplementationTypes = [];
- public static readonly Dictionary.KeyCollection ImplementedVersions;
-
- ///
- /// 静态构造函数
- ///
- static SkeletonConverter()
- {
- // 遍历并缓存标记了 SpineImplementationAttribute 的类型
- var impTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(SkeletonConverter).IsAssignableFrom(t) && !t.IsAbstract);
- foreach (var type in impTypes)
- {
- var attr = type.GetCustomAttribute();
- if (attr is not null)
- {
- if (ImplementationTypes.ContainsKey(attr.Version))
- throw new InvalidOperationException($"Multiple implementations found: {attr.Version}");
- ImplementationTypes[attr.Version] = type;
- }
- }
- Program.Logger.Debug("Find SkeletonConverter implementations: [{}]", string.Join(", ", ImplementationTypes.Keys));
- ImplementedVersions = ImplementationTypes.Keys;
- }
-
///
/// 创建特定版本的 SkeletonConverter
///
- public static SkeletonConverter New(Version version)
- {
- if (!ImplementationTypes.TryGetValue(version, out var cvterType))
- {
- throw new NotImplementedException($"Not implemented version: {version}");
- }
- return (SkeletonConverter)Activator.CreateInstance(cvterType);
- }
+ public static SkeletonConverter New(Version version) => New(version);
///
/// Json 格式控制
diff --git a/SpineViewer/Spine/Spine.cs b/SpineViewer/Spine/Spine.cs
index e6741f0..fcf5751 100644
--- a/SpineViewer/Spine/Spine.cs
+++ b/SpineViewer/Spine/Spine.cs
@@ -21,7 +21,7 @@ namespace SpineViewer.Spine
///
/// Spine 基类, 使用静态方法 New 来创建具体版本对象
///
- public abstract class Spine : SFML.Graphics.Drawable, IDisposable
+ public abstract class Spine : ImplementationResolver, SFML.Graphics.Drawable, IDisposable
{
///
/// 常规骨骼文件后缀集合
@@ -48,12 +48,6 @@ namespace SpineViewer.Spine
///
public const float SCALE_MIN = 0.001f;
- ///
- /// 实现类缓存
- ///
- private static readonly Dictionary ImplementationTypes = [];
- public static readonly Dictionary.KeyCollection ImplementedVersions;
-
///
/// 用于解决 PMA 和渐变动画问题的片段着色器
///
@@ -74,21 +68,6 @@ namespace SpineViewer.Spine
///
static Spine()
{
- // 遍历并缓存标记了 SpineImplementationAttribute 的类型
- var impTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(Spine).IsAssignableFrom(t) && !t.IsAbstract);
- foreach (var type in impTypes)
- {
- var attr = type.GetCustomAttribute();
- if (attr is not null)
- {
- if (ImplementationTypes.ContainsKey(attr.Version))
- throw new InvalidOperationException($"Multiple implementations found: {attr.Version}");
- ImplementationTypes[attr.Version] = type;
- }
- }
- Program.Logger.Debug("Find Spine implementations: [{}]", string.Join(", ", ImplementationTypes.Keys));
- ImplementedVersions = ImplementationTypes.Keys;
-
// 加载 FragmentShader
try
{
@@ -178,12 +157,7 @@ namespace SpineViewer.Spine
else
throw new InvalidDataException($"Auto version detection failed for {skelPath}, try to use a specific version");
}
- if (!ImplementationTypes.TryGetValue(version, out var spineType))
- {
- throw new NotImplementedException($"Not implemented version: {version}");
- }
-
- var spine = (Spine)Activator.CreateInstance(spineType, skelPath, atlasPath);
+ var spine = New(version, skelPath, atlasPath);
// 统一初始化
spine.initBounds = spine.Bounds;
@@ -233,7 +207,7 @@ namespace SpineViewer.Spine
atlasPath ??= Path.ChangeExtension(skelPath, ".atlas");
// 设置 Version
- Version = attr.Version;
+ Version = attr.ImplementationKey;
AssetsDir = Directory.GetParent(skelPath).FullName;
SkelPath = Path.GetFullPath(skelPath);
AtlasPath = Path.GetFullPath(atlasPath);
diff --git a/SpineViewer/Spine/Version.cs b/SpineViewer/Spine/SpineHelper.cs
similarity index 94%
rename from SpineViewer/Spine/Version.cs
rename to SpineViewer/Spine/SpineHelper.cs
index ee57bc7..3944aee 100644
--- a/SpineViewer/Spine/Version.cs
+++ b/SpineViewer/Spine/SpineHelper.cs
@@ -29,14 +29,9 @@ namespace SpineViewer.Spine
/// Spine 实现类标记
///
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
- public class SpineImplementationAttribute : Attribute
+ public class SpineImplementationAttribute(Version version) : Attribute, IImplementationKey
{
- public Version Version { get; }
-
- public SpineImplementationAttribute(Version version)
- {
- Version = version;
- }
+ public Version ImplementationKey { get; private set; } = version;
}
///