c # - Sådan kastes et objekt til IList < T > med ukendt type T

Indlæg af Hanne Mølgaard Plasc

Problem





Jeg har en object[] containig nogle værdier. Jeg ønsker at udtrække infomation ud af det, men jeg undlader at caste det andet objekt i arrayet (a WeakReference) til en IList med T som den tredje værdi i arrayet.



Tag et kig på min kode:


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


Eventuelle forslag til, hvordan jeg kan kaste målet for WeakReference til en IList-grænseflade med T=vals
object target = ((WeakReference)vals[2]).Target;

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

Bedste reference


Det er virkelig mærkeligt, at du pakker så meget heterogene informationer til et array . Arrays bruges normalt til at gemme elementer af typen samme . Hvorfor ikke indkapsles dataene i en korrekt type?


Men for at besvare spørgsmålet som spurgt - i C # 4 kan du bruge dynamic:


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

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


(EDIT: Hvis du vil minimere brugen af ​​dynamic her, kast til en WeakReference og lad det dynamiske opkald gå til slutningen. På denne måde er typesikkerheden maksimeret.)


Ellers kan du bruge refleksion:


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

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


(EDIT: Hvis indekseren kunne eksplicit implementeres, skal du sandsynligvis bruge grænseflademappings.)

Andre referencer 1


Det var allerede foreslået, at du kunne bruge dynamic, men det lyder som om du også skal kontrollere, at objektet har den angivne type. Jeg har også brugt dynamic til et minimum:


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;

Andre referencer 2


Hvis du bare har brug for objektet fra et tal, på et givet indeks, er det en simpel funktion, der gør det:


    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();
    }


Og i dit tilfælde ville du gøre dette:


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


Selvfølgelig er der alternativer, der ser mere sexet ud (se andre svar), med flotte linq-forespørgsler og coole C # 4 dynamiske nye trendy ting :-) men generelt, hvis du ikke behøver 'T-typen' (i dit eksempel kode, du behøver det ikke), du behøver ikke generiske. Denne løsning understøttes faktisk med .NET Framework og C # versioner fra 1 til 4.

Andre referencer 3


Jeg tror, ​​at du arbejder for hårdt for at kunne bruge de forlængelsesmetoder, som ikke synes at være nødvendige.


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