如果我有以下内容:
public abstract class Parameter<T>
{
protected T value;
public virtual T Value
{
get { return value; }
set { this.value = value; }
}
protected Parameter(T startingValue)
{
value = startingValue;
}
}
public class FloatParameter : Parameter<float>
{
public FloatParameter(float startingValue) : base(startingValue){}
}
public class IntParameter : Parameter<int>
{
public override int Value
{
get { return value; }
set { this.value = value > 100 ? 100 : value; }
}
public IntParameter(int startingValue) : base (startingValue) {}
}
有没有办法创建一些可以包含任何派生类型的List<Parameter>
?例如,像:
// no type specified in Parameter
List<Parameter> storedParameters = new List<Parameter>();
storedParameters.Add(new FloatParameter(2f));
storedParameters.Add(new IntParameter(7));
foreach(Parameter p in storedParameters)
{
DoSomethingWithValue(p.Value);
}
或者,如果这个实现存在缺陷,有没有更好的方法呢?我在这里感觉有些天真。
答案 0 :(得分:3)
我看到管理这种情况的唯一方法是使用和用于管理泛型类型的接口,这样的东西应该有效:
public interface IParameter
{
void DoSomething();
}
public abstract class Parameter<T>
{
protected T value;
public T Value
{
get { return value; }
set { this.value = value; }
}
protected Parameter(T startingValue)
{
value = startingValue;
}
}
public class FloatParameter : Parameter<float>, IParameter
{
public FloatParameter(float startingValue) : base(startingValue) { }
public void DoSomething()
{
Console.WriteLine(value);
}
}
public class IntParameter : Parameter<int>, IParameter
{
public IntParameter(int startingValue) : base(startingValue) { }
public void DoSomething()
{
Console.WriteLine(value);
}
}
根据他的情况,您将能够创建接口IParameter的List并添加特定的实例:
var list = new List<IParameter>();
list.Add(new FloatParameter(1F));
list.Add(new IntParameter(1));
foreach (var item in list)
{
item.DoSomething();
}
答案 1 :(得分:2)
尝试添加非通用接口。这是一个例子:
public class Program
{
static void Main(string[] args)
{
try
{
List<IParameter> storedParameters = new List<IParameter>();
storedParameters.Add(new FloatParameter(2f));
storedParameters.Add(new IntParameter(7));
foreach (IParameter p in storedParameters)
{
Console.WriteLine(p.ToString());
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
public interface IParameter
{
object value { get; }
}
public class Parameter<T> : IParameter
{
public object value { get; protected set; }
public virtual T Value
{
get { return (T)value; }
set { this.value = value; }
}
protected Parameter(T startingValue)
{
value = startingValue;
}
}
public class FloatParameter : Parameter<float>
{
public FloatParameter(float startingValue) : base(startingValue){ }
}
public class IntParameter : Parameter<int>
{
public override int Value
{
get { return (int)value; }
set { this.value = value > 100 ? 100 : value; }
}
public IntParameter(int startingValue) : base (startingValue) { }
}
答案 2 :(得分:1)
如果将值更改为对象,则可以将值设置为您喜欢的任何类型:
class Program
{
static void Main(string[] args)
{
// no type specified in Parameter
var storedParameters = new List<ParameterBase>();
storedParameters.Add(new FloatParameter(3.5F));
storedParameters.Add(new IntParameter(7));
foreach (var p in storedParameters)
{
Console.WriteLine(p.Value);
}
}
}
public class ParameterBase
{
protected object value;
public virtual object Value
{
get { return value; }
set { this.value = value; }
}
}
public class FloatParameter : ParameterBase
{
public FloatParameter(float value)
{
Value = value;
}
}
public class IntParameter : ParameterBase
{
public IntParameter(int value)
{
Value = value;
}
}
更新:使用对象而不是动态并删除了@Pieter Witvoet建议的ValueType
答案 3 :(得分:1)
不,这是不可能的。
您要做的是拥有一个公开未定义类型属性的接口(或基类),然后能够检索该值并将其动态分配给DoSomethingWithValue
的正确覆盖
您所追求的是可以将属性定义为dynamic
,而不是使用泛型。
public class Parameter
{
protected dynamic value;
public dynamic Value
{
get { return value; }
set { this.value = value; }
}
public Parameter(dynamic startingValue)
{
value = startingValue;
}
}
public class MyStuff {
public void DoStuff()
{
List<Parameter> storedParameters = new List<Parameter>();
storedParameters.Add(new Parameter(2f));
storedParameters.Add(new Parameter(7));
foreach (Parameter p in storedParameters)
{
DoSomethingWithValue(p.Value);
}
}
}
否则,您应该考虑实施Double dispatch
。
答案 4 :(得分:1)
您可以通过定义通用界面并使用访客模式来实现。
public interface IParameterVisitor
{
void VisitInt(int value);
void VisitFloat(float value);
}
public interface IParameter
{
void Accept(IParameterVisitor visitor);
}
之前的实现必须稍加修改:
public abstract class Parameter<T> : IParameter
{
protected T value;
public virtual T Value
{
get { return value; }
set { this.value = value; }
}
protected Parameter(T startingValue)
{
value = startingValue;
}
public abstract void Accept(IParameterVisitor visitor);
}
FloatParameter
将VisitFloat
,IntParameter
将VisitInt
public class FloatParameter : Parameter<float>
{
public FloatParameter(float startingValue) : base(startingValue) { }
public override void Accept(IParameterVisitor visitor)
{
visitor.VisitFloat(this.value);
}
}
public class IntParameter : Parameter<int>
{
public override int Value
{
get { return value; }
set { this.value = value > 100 ? 100 : value; }
}
public override void Accept(IParameterVisitor visitor)
{
visitor.VisitInt(this.value);
}
public IntParameter(int startingValue) : base(startingValue) { }
}
我们的访客例如:
public class MyVisitor : IParameterVisitor
{
public void VisitInt(int value)
{
Console.WriteLine($"Visiting an int: {value}");
}
public void VisitFloat(float value)
{
Console.WriteLine($"Visiting a float: {value}");
}
}
最后,用法:
var parameters =
new List<IParameter> {new FloatParameter(0.5f), new IntParameter(1)};
var visitor = new MyVisitor();
foreach (IParameter parameter in parameters) {
parameter.Accept(visitor);
}