Как привести объект к IList <T>с неизвестным типом T - PullRequest
3 голосов
/ 24 апреля 2011


У меня есть object[], содержащий некоторые значения. Я хочу извлечь из него информацию, но мне не удалось привести второй объект в массиве (a WeakReference) к IList с T в качестве третьего значения в массиве.

Посмотрите на мой код:

object[] vals = GetValues(); //vals[2] = WeakReference, vals[3] = Type of T, vals[4] = index in the list
IList<((Type)vals[3])> list = (IList<((Type)vals[3])>)(((WeakReference)vals[2]).Target); //This line does not even compile, seems like I'm doing something wrong..
object oo = list.ElementAt((int)vals[4]);
//Do something with oo...

Любые предложения, как я могу привести Target of WeakReference к интерфейсу IList с T = vals [3]?

Ответы [ 4 ]

4 голосов
/ 24 апреля 2011

Странно, что вы упаковываете столько разнородной информации в массив .Массивы обычно используются для хранения элементов типа того же .Почему бы не инкапсулировать данные в правильном типе?

Но чтобы ответить на вопрос в соответствии с заданным вопросом - в C # 4 вы можете использовать dynamic:

var target = ((dynamic)vals[2]).Target;

if(target != null)
{
    object oo = Enumerable.ElementAt(target, vals[4]);
    //Do something with oo...
}

(РЕДАКТИРОВАТЬ: если вы хотитечтобы минимизировать использование dynamic здесь, приведите к WeakReference и оставьте динамический вызов до конца. Таким образом, безопасность типов «максимизируется».)

В противном случае вы можете использовать отражение:

object target = ((WeakReference)vals[2]).Target;

if (target != null)
{
    object oo = target.GetType()
                      .GetProperty("Item")
                      .GetValue(target, new[] { vals[4] });
    //Do something with oo...
}

(РЕДАКТИРОВАТЬ: Если индексатор может быть явно реализован, вам, вероятно, потребуется использовать сопоставления интерфейса.)

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

Если вам просто нужен объект из перечислимого по заданному индексу, вот простая функция, которая делает это:

    public static object GetObjectAt(IEnumerable enumerable, int index)
    {
        int i = 0;
        foreach (object obj in enumerable)
        {
            if (i == index)
                return obj;

            i++;
        }
        throw new IndexOutOfRangeException();
    }

А в вашем случае вы бы сделали это:

        object oo = GetObjectAt((IEnumerable)(WeakReference)vals[2], (int)vals[4]);

Конечно, есть альтернативы, которые выглядят более сексуально (см. Другие ответы), с модными запросами linq и классными динамичными новинками C # 4 :-), но, в общем, если вам не «нужен» тип T ( в вашем примере кода это не нужно), вам не нужны генерики. Это решение фактически поддерживается любыми версиями .NET Framework и C #, от 1 до 4.

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

Уже предлагалось, что вы можете использовать dynamic, но похоже, что вы также должны проверить, что объект имеет указанный тип.Я также сохранил использование dynamic до минимума:

object target = ((WeakReference) vals[2]).Target;

if (target == null)
    throw new InvalidOperationException("Target cannot be null.");

object result = Enumerable.ElementAt((dynamic) target, (int) vals[4]);

if (result != null && !((Type) vals[3]).IsAssignableFrom(result.GetType()))
    throw new InvalidOperationException(string.Format("The retrieved object is a {0}, but the expected type was {1}.", result.GetType(), (Type) vals[3]));

return result;
1 голос
/ 24 апреля 2011

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

object[] vals = GetValues();
var list = ((WeakReference)vals[2]).Target as IList;
object oo = null;
if (list != null)
{
    oo = list[(int)vals[4]];
}
...