2011-04-25 72 views
0

我有两种方法,像这样:这是C#铸造无用?

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#的一个缺点?

注: 我知道我可以解决这个问题:

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

不过,我宁愿做这个wothout任何分配(在垃圾收集非常敏感的环境中工作)。

铌++: 奖励积分,如果你认为一个可选的非分配解决方案

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

+0

当你这样做会发生什么:'(T [])GetFoos(typeof运算(T))' – Will 2011-04-25 02:17:40

+0

请问:'InvalidCastException'。如果'as'返回'null',则直接投射将不会成功。 – Femaref 2011-04-25 02:18:57

+0

'GetFoos()'实现被锁定,你不能改变它?可能最理想的情况是(除了使用泛型),如果它返回一个非特定的'Array'。然后它可以返回一个这种类型的东西,你可以安全地将它转换为你需要的类型。 – 2011-04-25 02:32:31

回答

2

没有,C#铸造是不是没用 - 你根本无法投出Foo[]T[]其中T是一个更派生类型,因为Foo[]可以包含到T不同的其他元素。为什么不将GetFoos方法调整为GetFoos<T>()?只需要一个Type对象的方法可以很容易地转换为一个通用方法,您可以通过new T[]直接创建该数组。

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

编辑:

有来自Foo[]没有可能投给T[],在您的链接的描述是倒过来 - 你可以施放T[]Foo[]所有TFoo,但不是所有的FooT

+0

每次枚举它的时候不幸的枚举分配的阵列,这就是为什么我们”再在第一位置使用数组。服用类型的GetFoos查找在型 - 的字典阵列>富[],所以最终连通用方法将仍使用类型内部。我们不能存储更多的具体类型数组因为在字典中的所有值类型必须相同 – Martin 2011-04-25 02:20:58

+0

嗯,它分配一个'IEnumerator的',这是正确的,但它不会为每次每个元素分配内存。存储罪耗只取决于你的普查员数量。 – Femaref 2011-04-25 02:24:49

+0

对不起,通过“枚举?”我每次启动集合将分配(新的IEnumerator)的一个新的枚举时间的意思。我可以尝试p怂恿IEnumerator周围和调用重置批次,但这是可怕的丑陋! – Martin 2011-04-25 02:26:27

1

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

+0

这是一个有趣的事实。不幸的是在这种情况下,我觉得coverting使用新的T []将是困难的,因为在创建别的地方是什么都不知道的更多派生类型:( – Martin 2011-04-25 02:25:07

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

我觉得这个转换原地的,所以它不会做任何重新-allocations。

+0

不幸的是,从文档看起来它并不隐蔽在:( – Martin 2011-04-25 02:22:09

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... 

附注,您提供的节目阵列是如何协变的MSDN链接。也就是说,您可以将一个更多派生类型的数组存储在对基类型数组的引用中。你想在这里实现的是反变换(即,使用基类型的数组来代替更多派生类型的数组),这是另一种方式,以及在没有进行转换的情况下哪些数组无法做到。