这个C#铸造没用吗?

时间:2011-04-25 02:09:40

标签: c#-3.0 casting

我有两种方法:

Foo[] GetFoos(Type t) { //do some stuff and return an array of things of type T }

T[] GetFoos<T>()
    where T : Foo
{
    return GetFoos(typeof(T)) as T[];
}

但是,这似乎总是返回null。我做错了还是这只是C#的缺陷?

的Nb: 我知道我可以用以下方法解决这个问题:

GetFoos(typeof(T)).Cast<T>().ToArray();

但是,我更愿意做任何分配(在对垃圾收集非常敏感的环境中工作)。

铌++: 如果您建议替代非分配解决方案,则可获得奖励

编辑: 这提出了一个有趣的问题。这里的MSDN文档:http://msdn.microsoft.com/en-us/library/aa664572%28v=vs.71%29.aspx表示如果存在隐式或显式转换,则转换将成功。在这种情况下,有一个显式的强制转换,因此强制转换应该成功。 MSDN文档是错误的吗?

4 个答案:

答案 0 :(得分:2)

不,C#强制转换并非无用 - 您只是无法将Foo[]强制转换为T[] T,其中Foo[]是更多派生类型,T可能包含与GetFoos不同的其他元素。为什么不将GetFoos<T>()方法调整为Type?只接受new T[]对象的方法可以很容易地转换为通用方法,您可以通过Count直接创建数组。

如果这是不可能的:你是否需要数组提供的能力(即索引和IEnumerable<T>之类的东西)?如果没有,您可以使用Cast<T>.ToArray()而不会出现太多问题。如果不是:你不会绕过Foo[]方式。

编辑:

T[]T[]无法进行投射,您的链接中的描述则相反 - 您可以将Foo[]投射到T全部FooFoo,但并非所有T均为{{1}}。

答案 1 :(得分:1)

如果您可以安排GetFoos使用new T[]创建返回数组,那么您就赢了。如果你使用了new Foo[],那么数组的类型就固定了,无论它实际拥有的对象类型如何。

答案 2 :(得分:0)

我没试过这个,但它应该有效:

T[] array = Array.ConvertAll<Foo, T>(input,
    delegate(Foo obj)
    {
        return (T)obj;
    });

您可以在http://msdn.microsoft.com/en-us/library/exc45z53(v=VS.85).aspx

找到更多信息

我认为这会就地转换,所以它不会进行任何重新分配。

答案 3 :(得分:0)

根据我的理解,使用System.Array代替更具体的数组可以帮助您。请记住,Array是所有强类型数组的基类,因此Array引用实际上可以存储任何数组。你应该制作你的(通用?)字典映射Type -> Array,这样你就可以存储任何强类型数组,而不必担心需要将一个数组转换为另一个数组,现在它只是类型转换。

即,

Dictionary<Type, Array> myDict = ...;
Array GetFoos(Type t)
{
    // do checks, blah blah blah
    return myDict[t];
}
// and a generic helper
T[] GetFoos<T>() where T: Foo
{
    return (T[])GetFoos(typeof(T));
}

// then accesses all need casts to the specific type
Foo[] f = (Foo[])GetFoos(typeof(Foo));
DerivedFoo[] df = (DerivedFoo[])GetFoos(typeof(DerivedFoo));
// or with the generic helper
AnotherDerivedFoo[] adf = GetFoos<AnotherDerivedFoo>();
// etc...

p.s。,您提供的MSDN链接显示了数组的协变性。也就是说,您可以在对基类型数组的引用中存储更多派生类型的数组。你在这里想要实现的是逆变(即,使用基类型的数组代替更多派生类型的数组),这是另一种方式,没有进行转换,数组不能做什么。 / p>