假设我有一个通用类:
class Foo {
// protected Type t;
// public void SetT(string strval) {
// ((Foo<t>)this).Set(strval);
// }
}
class Foo<T> : Foo {
private T val;
public void Set(string strval) {
if (this is Foo<float>) {
this.val = float.Parse(strval);
} else if (this is Foo<int>) {
this.val = int.Parse(strval);
}
}
}
现在我创建一个对象并将其放在ArrayList中:
ArrayList a = new ArrayList();
a.Append(new Foo<float>);
然后我忘记了Foo&lt;&gt;的类型。现在,我该怎么设置?我尝试了明显的候选人:
(Foo)a[0].Set("5.0");
(Foo<a[0].GetType()>)a[0].Set("5.0");
但那些失败了。
有没有办法在没有明确知道Foo&lt;&gt;的类型的情况下调用Set方法?
如果没有,我可以以某种方式将Foo类型保存到Foo.t中,然后取消注释并使用Foo.SetT吗?
啊,仿制药。如果您知道如何使用它们,这是非常好的工具: - )此致 dijxtra
答案 0 :(得分:4)
一种方法是让你的通用Foo
类实现一个接口:
interface IFoo {
void Set(string strval);
}
class Foo<T> : IFoo {
private T val;
public void Set(string strval) {
...
}
}
然后你可以转发IFoo
并致电Set()
:
((IFoo)a[0]).Set("5.0");
答案 1 :(得分:3)
您希望覆盖派生类中Set
的实现。
class Foo {
public virtual void Set(string val);
}
class Foo<T> : Foo {
public override void Set(string val);
}
答案 2 :(得分:3)
绝对没有理由在这里使用泛型。当您将要执行的操作类型为 generic 时,将使用泛型。换句话说,它们独立于执行它们的类型。你正在做相反的事情:操作将不同取决于类型。< / p>
鉴于此,您应该删除泛型参数,make Set()
和Foo
abstract
,并派生相应的类来处理不同的类型:
abstract class Foo
{
public abstract void Set(string value);
}
class FooDouble : Foo
{
double val;
public override void Set(string value)
{
this.val = double.Parse(value);
}
}
// Etc.
然后,您应该将Foo
存储在List<T>
:
List<Foo> fooList = new List<Foo>();
fooList.Add(new FooDouble());
稍后,您可以这样说:
fooList[0].Set("5.0");
它会起作用!无需记住!
答案 3 :(得分:1)
除了Jimmy为您的基类指出的内容之外,您还可以使用泛型集合而不是ArrayList
并使用类型转换器:
public interface IFoo
{
void Set(string value);
}
public class Foo<T> : IFoo
{
private T val;
public void Set(string value)
{
var typeConverter = TypeDescriptor.GetConverter(typeof(T));
if(typeConverter.CanConvertFrom(typeof(string)))
{
val = (T)typeConverter.ConvertFromString(value);
}
else
{
throw new InvalidOperationException();
}
}
}
以上内容适用于您的ArrayList:
ArrayList a = new ArrayList();
a.Append(new Foo<float>());
((IFoo)a[0]).Set("123.4");
或使用类型化集合:
List<IFoo> list = new List<IFoo>();
list.Add(new Foo<float>());
list[0].Set("123.4");
作为额外的奖励,您无需在if
方法中使用Set
语句,并尝试考虑所有可能的类型。
答案 4 :(得分:0)
如果您想知道通用中使用的类型参数,请使用GetGenericArguments方法。
class Foo<T> {
int input_as_int;
float input_as_float;
public void Set(string strval) {
if (this.GetType().GetGenericArguments().First() == typeof(float)) {
this.input_as_float = float.Parse(strval);
} else if (this.GetType().GetGenericArguments().First() == typeof(int)) {
this.input_as_int = int.Parse(strval);
}
// Else .. throw an exception? return default value? return 0? what makes sense to your application
}
或者如果你可以通过完全传递接口并在构造函数中传递输入字符串。
public class Foo<T>
{
public Foo (string input)
{
var typeConverter = TypeDescriptor.GetConverter(typeof(T));
if (typeConverter.CanConvertFrom(typeof(string)))
{
Value = (T)typeConverter.ConvertFromString(input);
}
else
{
throw new InvalidOperationException();
}
}
public T Value { get; set;
}
}
那么你就可以这样使用它。
var test = new List<int> Foo ("3");
答案 5 :(得分:0)
using System;
using System.Collections;
using System.Collections.Generic;
class Foo {
}
class Foo<T> : Foo {
private T val;
public void Set(string strval) {
var _type = typeof(T);
val = (T)(_type.InvokeMember("Parse", System.Reflection.BindingFlags.InvokeMethod, null, null, new Object[] { strval }));
}
override public string ToString(){
return String.Format("{0}", val);
}
}
class Sample {
static void Main(string[] args){
ArrayList a = new ArrayList();
a.Add(new Foo<float>());
a.Add(new Foo<int>());
dynamic ax = a[0];
ax.Set("5.5");
ax = a[1];
ax.Set("55");
//EDIT
//But I may have to set the float value to Foo <int> If you forgot
// ((Foo<float>)a[0]).Set("5.5");
// ((Foo<int>)a[1]).Set("55");
Console.WriteLine("{0},{1}", a[0], a[1]);
}
}