Laden...

Via Reflection Generische Properties setzen

Erstellt von TBR vor 13 Jahren Letzter Beitrag vor 13 Jahren 798 Views
T
TBR Themenstarter:in
154 Beiträge seit 2009
vor 13 Jahren
Via Reflection Generische Properties setzen

Hallo, ich hab grad ein riesen Problem.

Ich arbeite momentan stark mit Reflection um mir hardcoded-Zeugs zu sparen.
Dabei hab ich folgende Klassen:

AssetData und AssetData<T>. Diese haben keinen geerbten Bezug, jedoch selbige Eigenschaften. Bei AssetData ist "Asset" ein object und bei "AssetData<T>" ist es eben "T".

Erstes brauch ich für allgemeine Arbeiten, wo ich nicht weiß was es für ein Typ ist.
"AssetData<T>" ist implizit castbar in AssetData - funktioniert.

Problem ist, ich muss bei einer PropertyInfo die z.B. den Typ "AssetData<Texture2D>" hat, ein AssetData setzen. Ich will nicht wieder was hardcoden, da ich bei neuen Typen sonst alle Codestellen erneuern muss, damit diese den Typ richtig verwenden oder erkennen.

Wie kann ich die nun am blödesten Setzen? Ich kann AssetData leider nicht casten, da ich den Typ "T" nicht habe. Im Grunde ist Asset bei beiden der gleiche Typ, jedoch erkennt er es logischerweise nicht so.

Gibt es eine Möglichkeit das zu umgehen? Ich muss irgendwie das object "Asset" von "AssetData" in das "T Asset" von "AssetData<T>" bringen.

Hier die Klassen:

    public class AssetData
    {
        public string AssetName;
        public Type AssetType;
        public object Asset;

        public bool IsQualified
        {
            get
            {
                return AssetName != "" & AssetType != null & Asset != null;
            }
        }
    }

    public class AssetData<T>
    {
        public static implicit operator T(AssetData<T> data)
        {
            return data.Asset;
        }

        public static implicit operator AssetData(AssetData<T> data)
        {
            return new AssetData
                       {
                           AssetName = data.AssetName,
                           AssetType = data.AssetType,
                           Asset = data.Asset
                       };
        }

        public static implicit operator AssetData<T>(AssetData data)
        {
            if (data.Asset != null) throw new NullReferenceException("Can´t cast AssetData because it´s Asset is null!");
            if (data.AssetType == typeof(T))
                return new AssetData<T>
                           {
                               AssetName = data.AssetName,
                               AssetType = data.AssetType,
                               Asset = (T) data.Asset
                           };

            throw new InvalidCastException("Could not cast AssetData with Asset '" + data.AssetType.Name +
                                           "' into AssetData<" + typeof (T).Name + ">!");
        }

        public string AssetName;
        public Type AssetType;
        public T Asset;

        public bool IsQualified
        {
            get
            {
                return AssetName != "" & AssetType != null & Asset != null;
            }
        }
    }

Danke euch 😃
TBR

6.862 Beiträge seit 2003
vor 13 Jahren

Hallo,

nicht die eigentliche Antwort auf deine Frage, aber der nicht generische Typ ist doch unnötig, da kannst du doch gleich einfach AssetData<object> für schreiben?!?

Von solchen Operatoren

        public static implicit operator T(AssetData<T> data)
         {
             return data.Asset;
         }
 

kann ich übrigens nur abraten. Das funktioniert zwar, aber Code der diese benutzt ist nur schwerlich auf den ersten Blick verständlich und noch schwerer zu warten, da ja überhaupt nicht von außen ersichtlich ist welche Eigenschaften von AssetData verwendet werden bei dem impliziten Cast. Ich würd eher ne Methode ala GetAsset<T>() für verwenden. Da wird nämlich sofort ersichtlich was gemacht wird im Gegensatz zum impliziten Cast.

Baka wa shinanakya naoranai.

Mein XING Profil.

T
TBR Themenstarter:in
154 Beiträge seit 2009
vor 13 Jahren

Verständlich, aber wir kommen da ganz gut mit klar 😉
Mir ist es nur lieber das implizit zu machen als explizit casten zu müssen, denn dann schlägt das wieder fail wenn man das per Reflection setzt, soweit ich weiß ...

Mich wundert nur, wieso AssetData den Operator haben muss, denn AssetData<T> ist von AssetData ja castbar, aber er will unbedingt den Operator von AssetData 😦

Irgendwie muss es doch ne Lösung geben 😕

EDIT: Bin haarscharf dran. Ich versuch es gerade so, und es geht beinahe. Problem ist wieder das Casten, da ich den Generischen Typ nicht hab...

                foreach (PropertyInfo pinf in comp.GetType().GetProperties())
                {
                    for (int i = 0; i < cdata.PInf.Count; i++)
                    {
                        if (cdata.PInf[i] != pinf.Name) continue;

                        AssetData assetData = new AssetData
                                                  {
                                                      AssetName = cdata.AN[i],
                                                      AssetType = Type.GetType(cdata.AT[i], true)
                                                  };
                        Application.Game.GetSystem<ContentManager>().LoadContent(ref assetData);

                        if (pinf.PropertyType.IsGenericType)
                        {
                            Type cast = pinf.PropertyType.GetGenericTypeDefinition().MakeGenericType(assetData.AssetType);
                            dynamic instance = Activator.CreateInstance(cast);
                            instance.AssetName = assetData.AssetName;
                            instance.Asset = Convert.ChangeType(assetData.Asset, assetData.AssetType);
                            instance.AssetType = assetData.AssetType;

                            pinf.SetValue(comp, instance, null);
                        }
                    }
                }

Problem ist, dass das Asset einfach nicht implizit konvertiert werden kann. Fällt wem ne spontane Lösung ein, wie man das umgeht?
So kurz vorm Durchbruch ...

Ich dreh noch durch damit 😄

EDIT2: Schade. Der Operator funktioniert hier nicht, denn sonst hätt ich das AssetData in das dynamische Objekt werfen können ... das dynamische ist jetzt z.B. "AssetData<Texture2D>", jedoch fehlen die Felder - der Operator überschreibt, und setzt nicht 😦

EDIT3: Problem gelöst.
AssetData hat eine generische Funktion "Cast<T>()" bekommen, welche ich per Reflection invoke und fertig:

                        if (pinf.PropertyType.IsGenericType)
                        {
                            MethodInfo method =
                                assetData.GetType().GetMethod("Cast").GetGenericMethodDefinition().MakeGenericMethod(
                                    assetData.AssetType);

                            dynamic castedAsset = method.Invoke(assetData, null);

                            pinf.SetValue(comp, castedAsset, null);
                        }