如何在C#泛型类中兼容System.Numerics与DoubleNumerics的Vector3
实现支持float/double双精度的泛型Vector3类
针对你的需求,这里提供两种高效的实现方案,避免直接使用object+强制转换的低效方式:
方案一:抽象接口+适配器模式(类型安全优先)
这种方式通过定义通用接口统一两种Vector3的访问逻辑,编译时即可保证类型安全,适合需要扩展Vector3功能的场景。
1. 定义通用Vector3接口
先定义包含核心属性的接口,可根据需求添加常用方法:
public interface IVector3<T> where T : struct { T X { get; set; } T Y { get; set; } T Z { get; set; } // 按需添加方法,如 Add、Subtract 等 }
2. 实现float/double版本的适配器
分别封装两个库的Vector3,实现通用接口,并添加隐式转换方便和原生类型互转:
Float版本适配器
using System.Numerics; public class FloatVector3Adapter : IVector3<float> { private Vector3 _innerVector; public FloatVector3Adapter(Vector3 vector) => _innerVector = vector; public float X { get => _innerVector.X; set => _innerVector.X = value; } public float Y { get => _innerVector.Y; set => _innerVector.Y = value; } public float Z { get => _innerVector.Z; set => _innerVector.Z = value; } // 隐式转换,直接用原生Vector3赋值/转换 public static implicit operator Vector3(FloatVector3Adapter adapter) => adapter._innerVector; public static implicit operator FloatVector3Adapter(Vector3 vector) => new FloatVector3Adapter(vector); }
Double版本适配器
using System.DoubleNumerics; public class DoubleVector3Adapter : IVector3<double> { private Vector3 _innerVector; public DoubleVector3Adapter(Vector3 vector) => _innerVector = vector; public double X { get => _innerVector.X; set => _innerVector.X = value; } public double Y { get => _innerVector.Y; set => _innerVector.Y = value; } public double Z { get => _innerVector.Z; set => _innerVector.Z = value; } public static implicit operator Vector3(DoubleVector3Adapter adapter) => adapter._innerVector; public static implicit operator DoubleVector3Adapter(Vector3 vector) => new DoubleVector3Adapter(vector); }
3. 改造泛型MyClass
public class MyClass<T> where T : struct { public IVector3<T> Coordinate { get; set; } // 默认构造函数,初始化对应精度的Vector3 public MyClass() { Coordinate = typeof(T) switch { Type t when t == typeof(float) => (IVector3<T>)(object)new FloatVector3Adapter(new System.Numerics.Vector3()), Type t when t == typeof(double) => (IVector3<T>)(object)new DoubleVector3Adapter(new System.DoubleNumerics.Vector3()), _ => throw new NotSupportedException($"不支持的类型:{typeof(T)}") }; } // 接受原生Vector3的构造函数,简化外部传入 public MyClass(System.Numerics.Vector3 vector) where T : float { Coordinate = (IVector3<T>)(object)new FloatVector3Adapter(vector); } public MyClass(System.DoubleNumerics.Vector3 vector) where T : double { Coordinate = (IVector3<T>)(object)new DoubleVector3Adapter(vector); } }
使用示例
// float精度实例 var floatObj = new MyClass<float>(); floatObj.Coordinate.X = 1.5f; // 直接转换为原生Vector3 System.Numerics.Vector3 nativeFloatVec = floatObj.Coordinate; // double精度实例 var doubleObj = new MyClass<double>(); doubleObj.Coordinate.Y = 3.14159; System.DoubleNumerics.Vector3 nativeDoubleVec = doubleObj.Coordinate;
方案二:动态类型+封装(简洁优先)
如果不想编写额外的适配器类,可以利用dynamic封装类型判断逻辑,外部使用时无需手动强制转换,代码更简洁(有轻微性能损耗,高频调用需注意)。
改造后的泛型MyClass
public class MyClass<T> where T : struct { private object _coordinate; // 对外暴露统一的X/Y/Z属性 public T X { get => GetComponent(v => v.X); set => SetComponent(v => v.X = value); } public T Y { get => GetComponent(v => v.Y); set => SetComponent(v => v.Y = value); } public T Z { get => GetComponent(v => v.Z); set => SetComponent(v => v.Z = value); } public MyClass() { _coordinate = typeof(T) switch { Type t when t == typeof(float) => new System.Numerics.Vector3(), Type t when t == typeof(double) => new System.DoubleNumerics.Vector3(), _ => throw new NotSupportedException($"不支持的类型:{typeof(T)}") }; } // 获取原生Vector3对象 public object GetNativeVector() => _coordinate; // 设置原生Vector3对象 public void SetNativeVector(object vector) { if (vector is System.Numerics.Vector3 floatVec && typeof(T) == typeof(float)) _coordinate = floatVec; else if (vector is System.DoubleNumerics.Vector3 doubleVec && typeof(T) == typeof(double)) _coordinate = doubleVec; else throw new ArgumentException("Vector类型与泛型参数不匹配"); } // 封装动态访问逻辑 private T GetComponent(Func<dynamic, T> getter) => getter((dynamic)_coordinate); private void SetComponent(Action<dynamic> setter) => setter((dynamic)_coordinate); }
使用示例
var floatInstance = new MyClass<float>(); floatInstance.X = 2.718f; // 获取原生Vector3时只需一次转换 var nativeFloat = (System.Numerics.Vector3)floatInstance.GetNativeVector(); var doubleInstance = new MyClass<double>(); doubleInstance.Z = 1.414; var nativeDouble = (System.DoubleNumerics.Vector3)doubleInstance.GetNativeVector();
方案选择
- 若追求类型安全且需要扩展Vector3的方法,优先选方案一;
- 若希望代码简洁、快速完成改造,且对性能要求不极致,选方案二。
内容的提问来源于stack exchange,提问作者Denzel
相关产品推荐
相关产品推荐

