Laden...

Generischer Typparameter T ist erst zu Laufzeit bekannt!?

Erstellt von Gepro vor 15 Jahren Letzter Beitrag vor 15 Jahren 1.983 Views
G
Gepro Themenstarter:in
419 Beiträge seit 2007
vor 15 Jahren
Generischer Typparameter T ist erst zu Laufzeit bekannt!?

nabend

ich habe eine methode, der ich den type bzw T mitgeben muss


        private bool BaseUpdateChangedObject<T>(object updateObject)
        {
             // usw...
        }

in einer anderen methode möchte ich diese aufrufen, kann aber nur dynamisch eventuell und nich direkt das T angeben


        public bool UpdateAllChangedObjects()
        {
            foreach (var obj in changedObjects)
            {
                BaseUpdateChangedObject</*?????*/>(obj);
            }

            return SubmitChanges();
        }


nur ich weiß nicht die richtige variable bzw p0latzhalter für T zu finden..
kann mir da jemand weiterhelfen ?

3.430 Beiträge seit 2007
vor 15 Jahren

Hallo Gepro,

wenn ich dich richtig verstanden habe, dann weisst du zur Laufzeit nicht genau welchen Typ du da mitgeben musst.
Und du willst dann also sowas wie einen Default-Typ mitgeben.

Dafür würde sich natürlich object eignen.

Gruss
Michael

G
Gepro Themenstarter:in
419 Beiträge seit 2007
vor 15 Jahren

das geht leider nicht, denn an der stelle streikt er und gibt mir nur ein Object zurück, und keine auflistung meiner Einträge in der Datenbank.


                var dbObject = dbContext.ExecuteQuery<T>(command, new object[0]).First();

5.942 Beiträge seit 2005
vor 15 Jahren

Hallo Gepro

Wie willst du einen Typ mitgeben, den du nicht kennst?
Bitte spezifiziere dein Problem / Aufgabe mal ein bisschen, sonst wird das schwierig.

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

G
Gepro Themenstarter:in
419 Beiträge seit 2007
vor 15 Jahren

in den changedObjects können objekte verschiedener klassen vorhanden sein, und um die datensätze mit hilfe des querys


 var dbObject = dbContext.ExecuteQuery<T>(command, new object[0]).First();

erhalten zu können brauchte ich den Typ.

nur "object.GetType()" bringt mir nichts, so geht das nicht, es geht nur wenn ich in dem methodenkopf das <T> reinschreibe und es in der methode anwende.


   private bool BaseUpdateChangedObject<T>(object updateObject) //where T : class
   {
      // usw...
      var dbObject = dbContext.ExecuteQuery<T>(command, new object[0]).First();
      // usw...
    }

nur in dieser auflistung sind objekte verschiedener klassen drinne, also kann ich keinen speziellen typ angeben. um die methode dynamisch zu halten muss ich halt einen anderen weg finden...


        public bool UpdateAllChangedObjects()
        {
            try
            { BaseUpdateChangedObject</*?*/>(changedObjects); }
            catch (Exception) { return false; }

            return SubmitChanges();
        }


5.942 Beiträge seit 2005
vor 15 Jahren

Hallo Gepro

Das geht so nicht, generische Typangaben müssen statisch sein, d.h. zur Compilezeit bekannt.
Du kannst sowas höchstens mit Reflection lösen, jedoch sehe ich da eher ein Designproblem als ein Problem mit der Technologie selber.

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

G
Gepro Themenstarter:in
419 Beiträge seit 2007
vor 15 Jahren

und wie soll ich das in diesem fall mit reflections lösen?
probier hier zwar rum, aber bekomm das nicht hin.

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo Gepro,

schreib doch bitte erstmal, warum du meinst, das zu brauchen. Peter Bucher hatte ja schon vermutet, dass das Design vielleicht nicht optimal ist. Dann wäre es ungünstig, Reflection zu nehmen.

herbivore

3.971 Beiträge seit 2006
vor 15 Jahren

Reflection ist da glaubig nicht so der Hit.

nur in dieser auflistung sind objekte verschiedener klassen drinne, also kann ich keinen speziellen typ angeben

Welche Klassen sind enthalten? Deine Eigenen? Gibts (außer System.Object) eine gemeinsame BasisKlasse?

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

G
Gepro Themenstarter:in
419 Beiträge seit 2007
vor 15 Jahren

von mir eigen erstelle klassen und es gibt keine basisklasse!!

ich zeig einfach mal den ganzen quellcode, is vllt besser:


       List<object> changedObjects = new List<object>();


        public bool UpdateAllChangedObjects()
        {
            try
            {
                 foreach(var obj changedObjects)
                {
                    BaseUpdateChangedObject</*?*/>(obj); 
                }
            }
            catch (Exception) { return false; }

            return SubmitChanges();
        }


        private bool BaseUpdateChangedObject<T>(object updateObject) //where T : class
        {
            try
            {
                // Tabelle des Objekts
                MetaTable table = dbContext.Mapping.GetTable(updateObject.GetType());

                // Identitäts-Eigenschaft, zum Erhalten des identischen Objekts aus der Datenbank
                string key == ""
                key = table.RowType.IdentityMembers[0].Name;

                // Wert der Primärschlüssel-Eigenschaft
                var value = updateObject.GetType().GetProperty(key).GetValue(updateObject, null);

                // Identisches Datenbank Objekt erhalten
                /*****************************************************************************/
                string tablename = dbContext.Mapping.GetTable(updateObject.GetType()).TableName;
                string command = "SELECT * FROM " + tablename + " WHERE (" + key + " = '" + value + "')";
                var dbObject = dbContext.ExecuteQuery<T>(command, new object[0]).First();

                // Werte gleich setzten
                /*****************************************************************************/
                foreach (PropertyInfo prop in dbObject.GetType().GetProperties())
                {
                    object resultValue = prop.GetValue(updateObject, null);
                    // Wert ersetzen
                    dbObject.GetType().GetProperty(prop.Name).SetValue(dbObject, resultValue, null);
                }

                // Objekt in die Liste mit veränderten Objekten speichern (falls Key noch nicht vorhanden)
                var countSameObject = (from o in changedObjects where o.GetType().GetProperty(key).GetValue(updateObject, null) == value select o).Count();
                if(countSameObject ==0)
                { changedObjects.Add(dbObject); }             
            }
            catch (Exception ex)
            {
                if (OnEditException != null) { OnEditException(ex, ChangeAction.Update); return false; }
            }
            return true;
        }

das ganze mache ich wegen mehrfach benutzungen der datenbank, ich hab schon gute gründe das so zu machen, nur ich könnte jetzt alle objekte einzelnt, nach den typen speichern (UpdateAllChangedObjects)

zb so


UpdateAllChangedObjects<IrgendeineKlasse>();
UpdateAllChangedObjects<NocheineKlasse>();

möchte aber alles, auf einmal machen, ohne bei der methode einen typen angeben zu müssen!

3.971 Beiträge seit 2006
vor 15 Jahren

Nimm (binäre) Serialisation, geht besser und es ist möglich, Klassen unterschiedlich zu speichern.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

G
Gepro Themenstarter:in
419 Beiträge seit 2007
vor 15 Jahren

@ eichhörnchen: ich möchte doch gar nichts speichern ?? versteh deine aussage total nicht , auch nicht mit dem binären serialisation

S
248 Beiträge seit 2008
vor 15 Jahren

Hallo Gepro,

ich habe zwar im Moment kein VS2008 zur Hand, aber versuche einmal

var dbObject = dbContext.ExecuteQuery<T>(command, new object[0]).First();

durch

T dbObject = dbContext.ExecuteQuery<T>(command, new object[0]).First();

zu ersetzten.

Spo

Edit:

Welche Signatur hat dbContext.ExecuteQuery<T>?

G
Gepro Themenstarter:in
419 Beiträge seit 2007
vor 15 Jahren

dann muss ich doch trotzdem das T angeben und dieses möchte ich auch gar nicht aus der BaseUpdateChangedObject<T> herausnehmen, sondern folgenden "Platzhalter" oder so für den Typen wissen


   public bool UpdateAllChangedObjects()
        {
            try
            {
                 foreach(var obj changedObjects)
                {
                    BaseUpdateChangedObject</*?*/>(obj);
                }
            }
            catch (Exception) { return false; }

            return SubmitChanges();
        }

3.971 Beiträge seit 2006
vor 15 Jahren

Bei Generics musst du einen Datentyp angeben und das schon zur Enwticklungszeit. Platzhalter oder sowas gibt es nicht.

Eine Möglichkeit (wurde bereits genannt), eine gemeinsame Basis-Klasse zu finden/entwerfen bzw. das ganze über ein Interface zu entkoppeln.

Es zwingt dich keiner Generics zu benutzen, besonders nicht, wenn es eine einfache Lösung ohne gibt.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

G
Gepro Themenstarter:in
419 Beiträge seit 2007
vor 15 Jahren

mhh..
ich muss zugeben, hört sich zwar nett an, mh doch ich verstehe nicht wirklich wie ich es nach deiner meinung umsetzten kann..
also basisklasse möchte ich auf jedenfall nicht verwenden, das auf keinen fall

5.942 Beiträge seit 2005
vor 15 Jahren

Salute Gepro

also basisklasse möchte ich auf jedenfall nicht verwenden, das auf keinen fall

Dann spricht doch nichts gegen ein Interface?

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

G
Gepro Themenstarter:in
419 Beiträge seit 2007
vor 15 Jahren

und wie soll ich das interface aufbauen ?
habe grade leider keine ahnung..
eine hilfe wär nich schlecht

3.971 Beiträge seit 2006
vor 15 Jahren

Abstrahieren!

Du hast eine handvoll Klassen, wo du mit allen das selbe machst (BaseUpdateChangedObject). Alle Eigenschaften und Funktionen, die BaseUpdateChangedObject braucht, lagerst du in eine seperates Interfaces aus.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...