找出泛型类的类型

时间:2011-10-23 01:58:26

标签: c# generics

假设我有一个通用类:

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

6 个答案:

答案 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]);
    }
}