C#的通用约束条件
我想创建一个通用(原文如此)的解决方案,让一个类有一堆属性。这些属性应该是简单类型(bool,int,float等)或复杂类型(向量,颜色等)。他们都应该有一种手段来解析他们从文本到他们的类型。C#的通用约束条件
的一个复杂类型,我打算在这里采用的是矢量:
public class Vector
{
private float _x, _y, _z;
public Vector(float x, float y, float z)
{
_x = x;
_y = y;
_z = z;
}
public Vector() : this(0.0f, 0.0f, 0.0f)
{
}
public float X
{
get { return _x; }
set { _x = value; }
}
public float Y
{
get { return _y; }
set { _y = value; }
}
public float Z
{
get { return _z; }
set { _z = value; }
}
}
下面是参数我的基类,它只是给它一个名字:
public class Parameter
{
protected string _name;
public Parameter() : this("untitled")
{
}
public Parameter(string name)
{
_name = name;
}
public string Name => _name;
}
这里的派生类它增加了一个通用类型TType的值,它有一个约束:
public class Parameter<TType> : Parameter where TType : ParameterValue<TType>
{
public Parameter(string name, TType value) : base(name)
{
Value = value;
}
public TType Value { get; set; }
}
现在这里是参数确保所有TTYPE对象都有一个解析函数
public abstract class ParameterValue<TType>
{
protected TType _value;
public ParameterValue(TType value)
{
_value = value;
}
public TType Value
{
get { return _value; }
set { _value = value; }
}
public abstract void Parse(string text);
}
这里值一般类的字符串定义:
public class StringValue : ParameterValue<string>
{
public StringValue(string value) : base(value)
{
}
public override void Parse(string text)
{
_value = text;
}
}
下面是向量的定义:
public class VectorValue : ParameterValue<Vector>
{
public VectorValue(Vector value) : base(value)
{
}
public override void Parse(string text)
{
var tokens = text.Split(',');
var x = float.Parse(tokens[0]);
var y = float.Parse(tokens[1]);
var z = float.Parse(tokens[2]);
_value = new Vector(x, y, z);
}
}
这里是我的经理类包含所有参数:
public class ParameterManager
{
private Dictionary<string, Parameter> _parameters;
public ParameterManager()
{
_parameters = new Dictionary<string, Parameter>();
}
public void AddParameter<TType>(string name, TType value) where TType : ParameterValue<TType>
{
_parameters[name] = new Parameter<TType>(name, value);
}
public TType FindParameterValue<TType>(string name) where TType : ParameterValue<TType>
{
var parameter = _parameters[name];
var parameterTyped = parameter as Parameter<TType>;
return parameterTyped?.Value;
}
}
现在,如果我创建使用ParamaterManager类,我打的问题:
public class Thing
{
private ParameterManager _parameters;
public Thing()
{
_parameters = new ParameterManager();
_parameters.AddParameter("name", new StringValue("untitled"));
_parameters.AddParameter("position", new VectorValue(new Vector()));
}
}
两行添加参数“名称”和“位置”抛出错误:
1>...\Thing.cs(11,13,11,37): error CS0311: The type 'ParameterProblem.StringValue' cannot be used as type parameter 'TType' in the generic type or method 'ParameterManager.AddParameter<TType>(string, TType)'. There is no implicit reference conversion from 'ParameterProblem.StringValue' to 'ParameterProblem.ParameterValue<ParameterProblem.StringValue>'.
1>...\Thing.cs(12,13,12,37): error CS0311: The type 'ParameterProblem.VectorValue' cannot be used as type parameter 'TType' in the generic type or method 'ParameterManager.AddParameter<TType>(string, TType)'. There is no implicit reference conversion from 'ParameterProblem.VectorValue' to 'ParameterProblem.ParameterValue<ParameterProblem.VectorValue>'.
我如何得到这个做我想要的?
where TType : ParameterValue<TType>
这是一个递归通用的限制,这将简化为TType : ParameterValue<XYZParameterValue>
其中XYZParameterValue : ParameterValue<TType>
这是不是你想要的,因为在你的情况下,实际的类型(例如string
)不不继承其相应ParameterValue
( ParameterValue<string>
)。使用由相同类型的,它是通用的过,像IComparable<T>
接口,其由类型T
(即System.String : IComparable<System.String>
)实现继承其上实现的通用接口/基类/时
你的通用约束会工作。
相反,我会做到以下几点:
public class Parameter<T> : Parameter
{
public Parameter(string name, ParameterValue<T> value) : base(name)
{
Value = value;
}
public ParameterValue<T> Value { get; set; }
}
你不得不改变ParameterManager
方法类似的形式过于:
public void AddParameter<T>(string name, ParameterValue<T> value)
{
_parameters[name] = new Parameter<TType>(name, value);
}
public ParameterValue<T> FindParameterValue<T>(string name)
{
var parameter = _parameters[name];
var parameterTyped = parameter as Parameter<TType>;
return parameterTyped?.Value;
}
旁注:命名类型约束TType
对于一般惯例没有任何意义,因为类型参数中的T
前缀表示“类型”,因此T
就足够了。
你的约束应与第二参数类型的变化来代替:
public void AddParameter<TType>(string name, ParameterValue<TType> value)
的呼声应该这样做:
_parameters.AddParameter<string>("name", new StringValue("untitled"));
_parameters.AddParameter<Vector>("position", new VectorValue(new Vector()));
我又是得太多 – imekon