C#泛型:我如何一般地使用它们?

时间:2010-12-22 19:56:48

标签: c# generics

[TestMethod]
public void TestMyGenericBaseClasses()
{ 
    Type typeCrazy = ThisPartyIsTypeCrazyWOOT();

    // How do I create a generic object?
    MadnessOhYeah<typeCrazy> sanity = new MadnessOhYeah<typeCrazy>();

    // How do I use a generic object after it has been created?
    Assert.IsTrue(sanity.MyTrueFunction(), "this is sparta");

    // How do I call a generic function generically?
    bool result = MyFunction<typeCrazy>();

    Assert.IsTrue(result, "I did not get my teeth whitened!");

}

有没有办法让这个编译? (ThisPartyIsTypeCrazyWOOT返回一个Type)因为这是一个测试,我们不关心必须使用反射或任何东西,除非那只是绝对疯狂。

我现在感受到这是不可能的,并且我们的测试功能必须更加具体。

2 个答案:

答案 0 :(得分:3)

答案 1 :(得分:2)

更新2 :我发布的第一个示例仍然没有100%回答问题,因为它涉及到List<int>的强制转换,这是一种已知的类型编译时间。下面是一个仅反射的解决方案,它说明了如何使用泛型类型,而对类型参数本身一无所知。但是,正如你所看到的,它......嗯,恶心;)

Type userType = GetUserSuppliedType();

// Now let's say userType is T.
// Then here we are getting the type typeof(List<T>).
// But, of course, there's no way to have any such information in the code.
Type listOfUserType = typeof(List<>).MakeGenericType(new[] { userType });

// This is effectively calling new List<T>();
object listObject = Activator.CreateInstance(listOfUserType);

// Do you see how messy this is getting?
MethodInfo addMethod = listOfUserType.GetMethod("Add");

// We better hope this matches userType!
object input = GetUserSuppliedInput();

// I suppose we could check it, to be sure...
if (input == null || input.GetType() != userType)
{
    throw new InvalidOperationException("That isn't going to work!");
}

// Here we are finally calling List<T>.Add(input) -- just in the most ass-
// backwards way imaginable.
addMethod.Invoke(listObject, new[] { input });

更新:好的,如果您坚持这样做,以下是可能的示例 - 但非常麻烦!

Type genericListType = typeof(List<>);
Type listOfInt32Type = genericListType.MakeGenericType(new[] { typeof(int) });

object listObject = Activator.CreateInstance(listOfInt32Type);

List<int> list = (List<int>)listObject;

list.Add(1);

泛型不能像这样工作,因为Type对象可能是任何东西。请考虑以下代码:

var list = new List<int>();
list.Add(1);

上述代码中list的类型为List<int>,它定义了list上合法的操作,例如Add(1)

现在考虑一下:

Type t = GetTypeFromIndeterminateSourceSuchAsUserInput();
var list = new List<t>();
list.Add(?);

tType个对象而不是编译器可以解析的类型的名称(如int)时,它就是&#39}不太可能使用该类型实例化泛型类型 - 或者更确切地说,可能(参见Andrey's answer),但您无法使用< / em>以任何通用方式生成的对象。

现在,你可能认为这样的事情应该有效:

Type t = typeof(int);
var list = new List<t>();
list.Add(1);

...但仅仅因为t的值在编译时已知(由你),并不会改变一般情况下的工作方式。

无论如何,是的,可以使用反射;但是,如果你沿着这条道路前进,那么你就会致力于一个反思很重的解决方案。我所得到的是,一般来说,这不是一件特别现实的事情。