[C#] Object at runtime aanmaken en de waarden erin aanpassen

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Ben_Beton
  • Registratie: Februari 2010
  • Laatst online: 12-09 08:59
De titel spreek voor zich denk ik, maar laat me even de situatie schetsen.

Ik lees uit een xml document allerlei waarden uit. Deze zijn onderverdeeld in 6 grote groepen.
Het xml document beschrijft een straaljager. dus heb ik een klasse shape geschreven. Nu zou ik verschillende objecten willen aanmaken waarbij de naam het onderdeel van de straaljager beschrijft.

Wat mij bij mijn vraag brengt, hoe maak ik een object aan at runtime en kan ik het later nog benaderen met:
Leftwing.color= "value"

Ik heb iets gelezen van Activator.CreateInstance? Maar ik geraak er niet echt wijs uit.

Met vriendelijke groet,
Ben

Acties:
  • 0 Henk 'm!

  • Kwistnix
  • Registratie: Juni 2001
  • Laatst online: 17-09 15:08
En over welke taal en/of platform hebben we het?

Edit: Oh C#, ben niet gewend om naar die tags te kijken, sorry.

[ Voor 41% gewijzigd door Kwistnix op 12-04-2012 17:02 ]


Acties:
  • 0 Henk 'm!

  • beany
  • Registratie: Juni 2001
  • Laatst online: 17-09 13:56

beany

Meeheheheheh

Als je een class hebt gemaakt, kan je die eenvoudig instancieeren:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Shape
{
   public string color;
}

class Program
{
   public void Main(string[] args)
   {
      Shape s = new Shape();
      s.color="value";
   }
}


Ofterwel: het 'new' keyword is het geen wat je zoekt denk ik ;)

edit: en als je nog op het niveau zit dat je bovenstaande niet weet moet je heeeeeeeeeeeeeeeel ver weg blijven van Activator.CreateInstance();

[ Voor 18% gewijzigd door beany op 12-04-2012 17:14 ]

Dagelijkse stats bronnen: https://x.com/GeneralStaffUA en https://www.facebook.com/GeneralStaff.ua


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

beany schreef op donderdag 12 april 2012 @ 17:13:
Ofterwel: het 'new' keyword is het geen wat je zoekt denk ik ;)
Ik denk eerder dat jij even goed moet kijken wat zijn vraag is. ;) Hij haalt een datastructuur uit een XML-file en op basis daarvan wil hij een object maken waarvan hij van tevoren de klassendefinitie niet kent. Die wil hij dus at run time maken in plaats van at compile time, dus domweg een shape instantiëren gaat niet werken als je een JetPlane.LetfWing.color = "value" wil doen, omdat een Shape geen LeftWing heeft. ;)

Hoe dat dan wel moet in C# weet ik overigens niet, en evenmin weet ik of dat eigenlijk wel een wenselijke aanpak is. Ik zou eerder kijken naar een andere structuur waar je code niet compleet variabel mee wordt.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • beany
  • Registratie: Juni 2001
  • Laatst online: 17-09 13:56

beany

Meeheheheheh

NMe schreef op donderdag 12 april 2012 @ 17:17:
[...]

Ik denk eerder dat jij even goed moet kijken wat zijn vraag is. ;) Hij haalt een datastructuur uit een XML-file en op basis daarvan wil hij een object maken waarvan hij van tevoren de klassendefinitie niet kent. Die wil hij dus at run time maken in plaats van at compile time, dus domweg een shape instantiëren gaat niet werken als je een JetPlane.LetfWing.color = "value" wil doen, omdat een Shape geen LeftWing heeft. ;)

Hoe dat dan wel moet in C# weet ik overigens niet, en evenmin weet ik of dat eigenlijk wel een wenselijke aanpak is. Ik zou eerder kijken naar een andere structuur waar je code niet compleet variabel mee wordt.
oeps... einde van de dag, niet geheel pittig meer...

In dat geval:

dynamic!

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
   class Shape
   {
      public string color;
   }
   class Program
   {
      static void Main(string[] args)
      {
         //of als je direct bij het type kan
         dynamic bla = new Shape();
         //of als je via variabelen de naam weet
         dynamic bla = Activator.CreateInstance("ConsoleApplication1", "ConsoleApplication1.Shape", null).Unwrap();

         bla.color = "sdf"; //dit wordt niet gechecked at compile time, maar opgezocht at runtime.
      }
   }


Inderdaad niet een handige manier. Anders via reflection, maar dan is bovenstaande schonere code, al kan je met reflection wel bekijken of properties bestaan of niet. Met Dynamic kan je overigens ook methodes aanroepen waarvan compiletime niet bekend is of ze er wel of niet zijn.

En als je de structuur helemaal niet weet(dus niet weet welke properties het gaat hebben) kan je of een propertybag op een standaard class maken(Dictionary<string, string>) of met Dynamic een propertybag maken waardoor properties direct in je code benaderbaar zijn. Zie de MSDN documentatie voor meer info.

[ Voor 15% gewijzigd door beany op 12-04-2012 17:27 ]

Dagelijkse stats bronnen: https://x.com/GeneralStaffUA en https://www.facebook.com/GeneralStaff.ua


Acties:
  • 0 Henk 'm!

  • Ben_Beton
  • Registratie: Februari 2010
  • Laatst online: 12-09 08:59
Toch nog effe vragen om zeker te zijn.
Bij die tweede methode wordt dan mijn bla (naam van het object) een variabele?
dus eigenlijk:

string bla = "leftwing"
dynamic bla= activator....

leftwing.color="sdf"

Dit zou dan moeten werken?

[ Voor 75% gewijzigd door Ben_Beton op 12-04-2012 19:07 ]


Acties:
  • 0 Henk 'm!

  • beany
  • Registratie: Juni 2001
  • Laatst online: 17-09 13:56

beany

Meeheheheheh

Voor het gebruik van CreateInstance moet je 2 dingen weten:

1. de assembly naam(ofterwel, de naam van de assembly waar de class zich in bevind)
2. de naam van de class incl. namespace

In mijn voorbeeld is de assembly naam ConsoleApplication1. De namespace is ook ConsoleApplication1 en de class naam is Shape wat resulteert in ConsoleApplication1.Shape voor de 2e parameter.

Belangrijk is dat de class(Shape in dit geval) dus al wel moet bestaan.

Het is ook mogelijk om een class runtime te creeeren, maar dan moet je je echt gaan afvragen of het wel de juiste manier is. Sterker nog: de dynamic variant is al erg dubieus.

Als je van te voren al weet wat de definities zijn, kan je ook met overerven gaan werken. Een base class maken en daar afgeleiden van maken. Weet je totaal niet welke properties je tegen gaat komen kan je mijn inziens het beste met property bags gaan werken(technisch niks meer dan een Dictionary<string, object>)

dus:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Onderdeel
{
   public Onderdeel Parent;
   public List<Onderdeel> Children;
   public string Naam;
   public Dictionary<string, string> Waardes;
}

Onderdeel vliegtuig = new Onderdeel() { Naam = "vliegtuig" };

Onderdeel vleugel = new Onderdeel() { Naam = "vleugel", Parent = vliegtuig };
vleugel.Waardes.Add("color", "pimpelpaars met groene vlekken");

vliegtuig.Children.Add(vleugel);


disclaimer: lange dag geweest, links en rechts een denk/interpretatie foutje is mogelijk :P

[ Voor 21% gewijzigd door beany op 12-04-2012 21:17 ]

Dagelijkse stats bronnen: https://x.com/GeneralStaffUA en https://www.facebook.com/GeneralStaff.ua


Acties:
  • 0 Henk 'm!

  • ViperNL
  • Registratie: Augustus 2008
  • Laatst online: 21:46
Voordat je met dynamic aan de slag gaat zou je eens moeten kijken of LINQ (to XML) niet gewoon voldoet..

Acties:
  • 0 Henk 'm!

  • D-Raven
  • Registratie: November 2001
  • Laatst online: 10-09 20:32
karatekid1990 schreef op donderdag 12 april 2012 @ 18:13:
Toch nog effe vragen om zeker te zijn.
Bij die tweede methode wordt dan mijn bla (naam van het object) een variabele?
dus eigenlijk:

string bla = "leftwing"
dynamic bla= activator....

leftwing.color="sdf"

Dit zou dan moeten werken?
Waarom moet die bla per see leftwing genaamd zijn? Het is een variabele, who ffing cares welke naam hij heeft?

Als leftwing zo'n belangrijke waarde is dan moet je hem opslaan in een property op t object.

daarnaast, als je het eenmaal voor elkaar hebt dat je je xml document omzet naar een dynamisch object, wat wil je er daarna mee doen dan?

[ Voor 11% gewijzigd door D-Raven op 12-04-2012 22:46 ]


Acties:
  • 0 Henk 'm!

  • HMS
  • Registratie: Januari 2004
  • Laatst online: 21-08 23:06

HMS

ViperNL schreef op donderdag 12 april 2012 @ 21:29:
Voordat je met dynamic aan de slag gaat zou je eens moeten kijken of LINQ (to XML) niet gewoon voldoet..
Eens. Wat is er op tegen om het document te parsen en dan gewoon objecten aanmaken en de values invullen?

Acties:
  • 0 Henk 'm!

  • Ben_Beton
  • Registratie: Februari 2010
  • Laatst online: 12-09 08:59
Wel niets:)
Maar het was mooi geweest omdat ik graag iets reproduceerbaar had gemaakt.

Ik weet wat er in de xml file staat, en tuurlijk dat kan ik gaan bekijken en dan die objecten al aanmaken. Maar waar is de lol dan?:)
Maar ik heb het nu als volgt opgelost:
Ik heb de class shape aangemaakt waarin alle properties van de xml komen te staan, en deze voeg ik elke keer toe aan een list<shape> Lijst. Op deze manier hoef ik ook niet elk object een naam te geven.

Ik had graag nog even gehoord wat jullie van deze oplossing denken?:)

edit: wat de uiteindelijke bedoeling is, is een vliegtuig tekenen in c# met opengl. De coordinaten en lichteigenschappen staan bijvoorbeeld in de xml.

[ Voor 12% gewijzigd door Ben_Beton op 13-04-2012 00:12 ]


Acties:
  • 0 Henk 'm!

  • HMS
  • Registratie: Januari 2004
  • Laatst online: 21-08 23:06

HMS

Ik bedoelde dan ook natuurlijk at runtime de XML parsen ;)

Als het de structuur heeft van:

XML:
1
2
3
4
5
<object>
  <shape>properties ofzo</shape>
  <shape>...</shape>
  ....
</object>


dan kan je met een simpele XML parser er zo door heen. De objecten on the fly aanmaken en dan in een lijst stoppen.

Ik weet niet hoe je het nu hebt opgelost, maar het klinkt alsof je het op deze manier hebt gedaan :P

Acties:
  • 0 Henk 'm!

  • Ben_Beton
  • Registratie: Februari 2010
  • Laatst online: 12-09 08:59
Ik geloof van wel. Dit is een klein deel XML

XML: filename
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 {
<Transform>
        <Shape DEF='rightwing'>
          <Appearance>
            <Material
              ambientIntensity='0.2'
              diffuseColor='1.0 1.0 1.0'
              emissiveColor='0 0 0'
              shininess='0.2'
              specularColor='0 0 0'
              transparency='0'
            />
          </Appearance>
          <IndexedFaceSet
            coordIndex='        
              0, 14, 27, -1,
              1, 15, 14, -1,
              2, 16, 15, -1} 


En hier staat een stukje c# hoe het gedaan is nu:
C#: filename
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 {
List<Shape> Lijst = new List<Shape>();
                XmlTextReader reader = new XmlTextReader("F16.x3d");
                reader.WhitespaceHandling = WhitespaceHandling.None;
                while (reader.Read())
                {
                    Shape shape = new Shape();
                    reader.ReadToFollowing("Shape");
                    if (reader.Name == "Shape")
                    {
                        shape.DEF = reader.GetAttribute("DEF");
                        reader.ReadToFollowing("Material");
                        Console.WriteLine(reader.GetAttribute("ambientIntensity"));
                        Console.WriteLine(shape.DEF);
                        Console.WriteLine(shape.ambientIntensity);
                    }
                    Lijst.Add(shape);

} 

Acties:
  • 0 Henk 'm!

  • epic007
  • Registratie: Februari 2004
  • Laatst online: 25-08 11:27
Wil je niet een Dictionary gebruiken ipv List?

C#:
1
2
3
4
5
6
7
8
9
Dictionary<string, Shape> shapes;

// tijdens parsen
shapes["Leftwing"] = new Shape(...);
shapes["Rightwing"] = new Shape(...);


// en later..
shapes["Leftwing"].color = Blue;

Acties:
  • 0 Henk 'm!

  • SaphuA
  • Registratie: September 2005
  • Laatst online: 10-09 22:00
.

[ Voor 121% gewijzigd door SaphuA op 31-01-2022 15:28 ]


Acties:
  • 0 Henk 'm!

  • HMS
  • Registratie: Januari 2004
  • Laatst online: 21-08 23:06

HMS

Maar als je arbitraire 'complexe' objecten wil renderen (of wat dan ook), dan is zijn oplossing een stuk herbruikbaarder.

Acties:
  • 0 Henk 'm!

  • Russel88
  • Registratie: Juli 2009
  • Laatst online: 00:41
Wat je wilt doen heet reflectie. Google daar maar eens op. Is leuk en soms handig, maar ik zou het alleen gebruiken als het echt niet anders kan.
Hier een opzetje hoe je het kan oplossen, syntax zal niet helemaal kloppen en sommige code weet ik zo niet uit m'n hoofd. Gaat om het idee :):
XMLDocument myXmlDoc = new XmlDocument("jeXMLBestand");
List<Shape> Lijst = new List<Shape>();
foreach(XmlNode shapeNode in myXmlDoc.SelectNodes("Shapes"))
{
Shape shape = new Shape();
foreach(atrribute shapeattrib in shapeNode.attribues) // Ben de syntaxt vergeten,
{
PropertyInfo pi = typeof(Shape).GetPropertyInfo(shapeattrib.Name) //shapettrib.Value moet dan Def zijn
if(pi != nulll)
{
pi.SetValue(shape, shapeattrib.Value); //shapettrib.Value is in je voorbeeld "rightwing"
}

}
Lijst.Add(shape);
}
Pagina: 1