我正在尝试编写一个可以表示Forces和Dimensions的Vector类。通常这不是问题,因为大多数人都会创建一个名为Magnitude的属性,它返回一个double。 Double不关心他们代表什么,他们代表力量或尺寸就好了。但是,我使用this open-source library called Unit Class Library来表示维度和力量。
这是我想做的事情。有没有办法让属性返回一个不同的类型,具体取决于T
(在构造函数中会发生同样的事情)。是否有可能,如果是这样,怎么样?
public class Vector<T> : LineSegment
{
ForceUnit _magnitudeForce;
/// <summary>
/// Returns the magnitude of the vector (equals the length of the line segment parent if T is Dimension, if T is Force, return variable )
/// </summary>
public T Magnitude
{
get {
Type typeT = typeof(T);
if (typeT == typeof(Dimension))
{
return base.Length;
}
else if (typeT == typeof(ForceUnit))
{
return _magnitudeForce;
}
...
}
或者,使用dynamic
关键字可以做些什么来实现这个目标?
或者我应该将这样的一组接口放在Unit Library:
之上interface IDistance
{
double Centimeters { get; }
double Feet { get; }
double Inches { get; }
double Kilometers { get; }
double Meters { get; }
double Miles { get; }
double Millimeters { get; }
double Sixteenths { get; }
double ThirtySeconds { get; }
double Yards { get; }
}
interface IForceUnit
{
double Kips { get; }
double Newtons { get; }
double Pounds { get; }
}
然后创建一个Hybrid类,实现两者作为Class的Magnitude。
我运行Unit Class Library因此欢迎提出应该进行的任何更改。但请记住,库的直观性和单位转换能力是我想要保留的项目的价值。
答案 0 :(得分:2)
你绝对不想做那种类型检查 - 你最好做的是创建一个抽象基类或接口,然后从中派生。
例如,如果您使用抽象类:
public abstract class Vector<T> : LineSegment
{
public abstract T Magnitude { get; }
}
public class DimensionVector : Vector<Dimension>
{
public override Dimension Magnitude { get { return base.Length; } }
}
public class ForceUnitVector : Vector<ForceUnit>
{
ForceUnit magnitudeForce;
public override ForceVector Magnitude { get { return this.magnitudeForce; } }
}
答案 1 :(得分:2)
让我提供和替代单位库。这将使您不必处理泛型,并可以使用派生单位。以下是第一个例子:
class Program
{
static void Main(string[] args)
{
Vector A=new Vector(Unit.Foot, 0.3, 0.5, 0.7, 1.0);
Vector B=A.ConvertTo(Unit.Inch);
Vector C=B*B; // Convert to square inches, compatible with SI units of m^2
Debug.WriteLine(A.ToString()); // [0.3,0.5,0.7,1]
Debug.WriteLine(B.ToString()); // [3.6,6,8.4,12]
Debug.WriteLine(C.ToString()); // [12.96,36,70.56,144]
Vector F=new Vector(Unit.PoundForce, 100.0, 130.0, 150.0, 180.0);
Vector K=F/B; // Stiffness is force per distance, compatible with SI units of kg/m^2
Vector P=F/C; // Pressure is force per area, compatible with SI units kg/(m*s^2)
Debug.WriteLine(F.ToString()); // [100,130,150,180]
Debug.WriteLine(K.ToString()); // [27.78,21.67,17.86,15]
Debug.WriteLine(P.ToString()); // [7.716,3.611,2.126,1.25]
var x=3*Unit.Foot.FactorTo(Unit.Inch); // x=36 inches
}
}
Unit
类是:
public class Unit : IEquatable<Unit>
{
readonly int M, L, T; // base unit powers. For example Area: (M=0, L=2, T=0)
readonly double x; // base unit factor. For example 1 km = (1000)*m
public Unit(int M, int L, int T, double factor)
{
this.M=M;
this.L=L;
this.T=T;
this.x=factor;
}
public Unit(Unit other)
{
this.M=other.M;
this.L=other.L;
this.T=other.T;
this.x=other.x;
}
public int[] Dimension { get { return new int[] { M, L, T }; } }
public double Factor { get { return x; } }
public bool IsConvertibleTo(Unit other) { return M==other.M&&L==other.L&&T==other.T; }
public double FactorTo(Unit target)
{
if(IsConvertibleTo(target))
{
return Factor/target.Factor;
}
throw new ArgumentException("Incompatible units in target.");
}
#region IEquatable Members
/// <summary>
/// Equality overrides from <see cref="System.Object"/>
/// </summary>
/// <param name="obj">The object to compare this with</param>
/// <returns>False if object is a different type, otherwise it calls <code>Equals(Unit)</code></returns>
public override bool Equals(object obj)
{
if(obj is Unit)
{
return Equals((Unit)obj);
}
return false;
}
/// <summary>
/// Checks for equality among <see cref="Unit"/> classes
/// </summary>
/// <param name="other">The other <see cref="Unit"/> to compare it to</param>
/// <returns>True if equal</returns>
public bool Equals(Unit other)
{
return M==other.M
&&L==other.L
&&T==other.T
&&x.Equals(other.x);
}
/// <summary>
/// Calculates the hash code for the <see cref="Unit"/>
/// </summary>
/// <returns>The int hash value</returns>
public override int GetHashCode()
{
return (((17*23+M.GetHashCode())*23+L.GetHashCode())*23+T.GetHashCode())*23+x.GetHashCode();
}
#endregion
public override string ToString()
{
return string.Format("{0}(M:{1},L:{2},T:{3})", Factor, M, L, T);
}
public static Unit operator*(double relative, Unit unit)
{
return new Unit(unit.M, unit.L, unit.T, relative*unit.Factor);
}
public static Unit operator/(Unit unit, double divisor)
{
return new Unit(unit.M, unit.L, unit.T, unit.Factor/divisor);
}
public static Unit operator*(Unit unit, Unit other)
{
return new Unit(
unit.M+other.M,
unit.L+other.L,
unit.T+other.T,
unit.Factor*other.Factor);
}
public static Unit operator/(Unit unit, Unit other)
{
return new Unit(
unit.M-other.M,
unit.L-other.L,
unit.T-other.T,
unit.Factor/other.Factor);
}
public static Unit operator^(Unit unit, int power)
{
return new Unit(
unit.M*power,
unit.L*power,
unit.T*power,
Math.Pow(unit.Factor, power));
}
public static readonly Unit Meter=new Unit(0, 1, 0, 1.0);
public static readonly Unit Millimeter=0.001*Meter;
public static readonly Unit Inch=25.4*Millimeter;
public static readonly Unit Foot=12*Inch;
public static readonly Unit Yard=3*Foot;
public static readonly Unit Second=new Unit(0, 0, 1, 1.0);
public static readonly Unit Minute=60*Second;
public static readonly Unit Hour=60*Minute;
public static readonly Unit Kilogram=new Unit(1, 0, 0, 1.0);
public static readonly Unit PoundMass=0.453592*Kilogram;
public static readonly Unit Newton=Kilogram*(Meter/(Second^2));
public static readonly Unit PoundForce=4.44822162*Newton;
}
将在Vector
类
public class Vector
{
public Vector(Unit unit, int size)
{
this.Elements=new double[size];
this.Unit=unit;
}
public Vector(Unit unit, params double[] values)
{
this.Unit=unit;
this.Elements=values;
}
public Unit Unit { get; private set; }
public double[] Elements { get; private set; }
public double this[int index] { get { return Elements[index]; } }
public int Count { get { return Elements.Length; } }
public Vector ConvertTo(Unit target)
{
double factor=Unit.FactorTo(target);
double[] values=Array.ConvertAll(Elements, (x) => factor*x);
return new Vector(target, values);
}
public override string ToString()
{
string[] items=Array.ConvertAll(Elements, (x) => x.ToString());
return string.Format("[{0}] in {1}", string.Join(",", items), Unit.ToString());
}
public static Vector operator+(Vector x, Vector y)
{
if(x.Count==y.Count)
{
x=x.ConvertTo(y.Unit);
double[] result=new double[x.Count];
for(int i=0; i<result.Length; i++)
{
result[i]=x[i]+y[i];
}
return new Vector(y.Unit, result);
}
throw new IndexOutOfRangeException("Vectors must have the same number of elements.");
}
public static Vector operator-(Vector x, Vector y)
{
if(x.Count==y.Count)
{
x=x.ConvertTo(y.Unit);
double[] result=new double[x.Count];
for(int i=0; i<result.Length; i++)
{
result[i]=x[i]-y[i];
}
return new Vector(y.Unit, result);
}
throw new IndexOutOfRangeException("Vectors must have the same number of elements.");
}
public static Vector operator*(double x, Vector y)
{
double[] result=new double[y.Count];
for(int i=0; i<result.Length; i++)
{
result[i]=x*y[i];
}
return new Vector(y.Unit, result);
}
public static Vector operator*(Vector x, Vector y)
{
if(x.Count==y.Count)
{
double[] result=new double[x.Count];
for(int i=0; i<result.Length; i++)
{
result[i]=x[i]*y[i];
}
return new Vector(x.Unit* y.Unit, result);
}
throw new IndexOutOfRangeException("Vectors must have the same number of elements.");
}
public static Vector operator/(Vector x, Vector y)
{
if(x.Count==y.Count)
{
double[] result=new double[x.Count];
for(int i=0; i<result.Length; i++)
{
result[i]=x[i]/y[i];
}
return new Vector(x.Unit/y.Unit, result);
}
throw new IndexOutOfRangeException("Vectors must have the same number of elements.");
}
}
答案 2 :(得分:2)
为什么不从Vector派生并丢弃作为Dimension的父Magnitude值?
有这样的东西吗?
public class Load:Vector
{
private ForceUnit _magnitude;
public ForceUnit Magnitude
{
get
{
return this._magnitude;
}
}
public PointLoad(ForceUnit magnitudeOfLoad, Vector directionVector)
: base(...)
{
_magnitude = magnitudeOfLoad;
}
}
答案 3 :(得分:1)
您可以返回一个对象或动态,并将其强制转换。
但是,我建议你不要这样做,即使没有意义。 我建议你检查一下你的逻辑。
public object Magnitude
{
get {
Type typeT = typeof(T);
if (typeT == typeof(Dimension))
{
return base.Length;
}
else if (typeT == typeof(ForceUnit))
{
return _magnitudeForce;
}
...
}