Это C # литье бесполезно? - PullRequest
       47

Это C # литье бесполезно?

0 голосов
/ 25 апреля 2011

У меня есть два метода, таких как:

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[];
}

Однако, это всегда кажется нулевым. Я делаю что-то неправильно или это просто недостаток C #?

Nb: Я знаю, что могу решить эту проблему с помощью:

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

Однако я бы предпочел сделать это без каких-либо выделений (работая в среде, очень чувствительной к сборкам мусора).

Nb ++: Бонусные баллы, если вы предлагаете альтернативное нераспределительное решение

Изменить: Это поднимает интересный вопрос. Документы MSDN здесь: http://msdn.microsoft.com/en-us/library/aa664572%28v=vs.71%29.aspx говорят, что приведение будет успешным, если будет приведено неявное или явное приведение. В этом случае существует явное приведение, и поэтому приведение должно быть успешным. Документы MSDN неверны?

Ответы [ 4 ]

2 голосов
/ 25 апреля 2011

Нет, приведение C # не бесполезно - вы просто не можете привести Foo[] к T[], где T является более производным типом, так как Foo[] может содержать другие элементы, отличные от T.Почему бы вам не настроить GetFoos метод на GetFoos<T>()?Метод, использующий только объект Type, может быть легко преобразован в универсальный метод, в котором вы можете создать массив напрямую с помощью new T[].

Если это невозможно: нужны ли вам возможности, предлагаемые массивом(т.е. индексирование и тому подобное Count)?Если нет, вы можете работать с IEnumerable<T> без особых проблем.Если нет: вам не удастся пройти по пути Cast<T>.ToArray().

Редактировать:

Невозможно выполнить приведение от Foo[] до T[], описание в вашей ссылкенаоборот - вы можете разыграть T[] до Foo[], поскольку все T равны Foo, но не все Foo равны T.

1 голос
/ 25 апреля 2011

Если вы можете организовать GetFoos для создания возвращаемого массива, используя new T[], то вы выиграете.Если вы используете new Foo[], то тип массива будет фиксированным, независимо от типов объектов, которые он фактически содержит.

0 голосов
/ 25 апреля 2011

Насколько я понимаю из вашей ситуации, использование 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 показывает ковариантность массивов. То есть вы можете хранить массив более производного типа в ссылке на массив базового типа. Здесь вы пытаетесь достичь контравариантности (т. Е. Использования массива базового типа вместо массива более производного типа), что является противоположным способом, и что массивы не могут сделать без преобразования.

0 голосов
/ 25 апреля 2011

Я не пробовал это, но оно должно работать:

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

Я думаю, что это конвертирует на месте, поэтому не будет перераспределять.

...