[C#/Reflection] Hoe te bepalen wat een struct is

Pagina: 1
Acties:

  • zoepercavia
  • Registratie: September 2001
  • Laatst online: 26-12-2025
Probleem: Ik moet bepalen of een type een struct is door middel van reflectie (met System.Reflection). Ik kan echter niet vinden hoe ik een struct moet onderscheiden van andere types. Wie kan mij vertellen hoe een struct te onderscheiden van bijvoorbeeld een Int32?

Wat heb ik zelf al gedaan: Gegoogled natuurlijk :) Ik krijg daar wel wat aanwijzingen, met IsValueType kom je een stukje, maar een int32 is ook een valuetype en gaat het dus mis. In http://www.only4gurus.com/techlib/miscellaneous/m2.pdf (pagina 4) staat dit. Zoiets als Type.IsStruct bestaat niet :(
Andere dingen die structs onderscheiden van andere types kan ik niet vinden.

Misschien weet iemand dit? Het zoekt vrij lastig op internet.

Panacea.NL als je geinteresserd bent in IT en Geneeskunde!


  • EfBe
  • Registratie: Januari 2000
  • Niet online
De vraag is: waarom wil je dit weten? Want wellicht zijn er andere oplossingen mogelijk die je ook brengen waar je naar toe wilt :)

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • marcusk
  • Registratie: Februari 2001
  • Laatst online: 26-09-2023
Een Int32 (met hoofdletter dus) is ook een struct :)

Het type is alleen maar speciaal omdat het er in C# automatische conversie is naar en van int (autoboxing).

  • zoepercavia
  • Registratie: September 2001
  • Laatst online: 26-12-2025
Grmmbll.. ik vermoedde al zoiets met die Int32.

Ik ben al een tijdje met een object-relationele mapper bezig en dit is voor de code generator. Ik wil structs (=value type) persisteren dmv embedded value (Fowler, PEAA). Een struct (met meerdere velden) wordt dus gemapped naar meerdere kolommen in de database. Ik moet een veld dat als basis type struct heeft dus anders persisteren dan een veld dat maar naar 1 kolom mapt. Daarvoor moet ik dus wel weten of een type een struct is :)

Zoals gezegd genereer ik de mapper dmv reflectie. Als het niet mogelijk is om custom structs ('eigen' structs), te onderscheiden van basis types zoals Int32, dan vrees ik dat dat een doodlopende weg is. Ik denk dat ik dan maar met attributes ga aangeven of een struct wel of niet gepersisteerd dient te worden.

Panacea.NL als je geinteresserd bent in IT en Geneeskunde!


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Structs worden eigenlijk alleen gebruikt voor het vasthouden van een speciale waarde, zoals "ComplexNumber" e.d. In .NET gebruik je geen structs zoals je dat deed/doet in C++ of C. Ik zou er niet zo wakker van liggen, je kunt denk ik het beste de structs naar 1 field mappen, 10 tegen 1 dat je daar geen moeilijkheden mee krijgt.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • zoepercavia
  • Registratie: September 2001
  • Laatst online: 26-12-2025
EfBe schreef op 21 August 2003 @ 09:13:
Structs worden eigenlijk alleen gebruikt voor het vasthouden van een speciale waarde, zoals "ComplexNumber" e.d. In .NET gebruik je geen structs zoals je dat deed/doet in C++ of C. Ik zou er niet zo wakker van liggen, je kunt denk ik het beste de structs naar 1 field mappen, 10 tegen 1 dat je daar geen moeilijkheden mee krijgt.
Je bedoelt dan dus door ze te serialiseren? Op dit moment heb ik bijvoorbeeld een adres als een struct, als ik deze met bijvoorbeeld XML serialiseer en dan in een kolom stop dan kan niet meer makkelijk queries loslaten om bijvoorbeeld 1 straat te zoeken.
Of ik zou van de struct een class moeten maken. Even afgezien van het feit dat volgens mij value types voor dingen zoals adressen ideaal zijn, betekent het dat dat adres in een aparte tabel moet, wat weer slecht is voor de performance.

Panacea.NL als je geinteresserd bent in IT en Geneeskunde!


  • marcusk
  • Registratie: Februari 2001
  • Laatst online: 26-09-2023
Wat ik eerder zei klopt niet helemaal: Ik dacht dat een .NET Int32 equivalent is aan een Java Integer, dus een wrapper om een int. In C# is int echter een alias voor Int32. 'int i' is dus precies hetzelfde als 'Int32 i'. Het type is dus wel degelijk 'speciaal'. Naar mijn weten is er echter geen mooie manier om deze 'simpel types' van andere value types te onderscheiden. Maar aangezien er maar beperkt aantal zijn (13, zie hier) kun je hier wel zelf een methode voor schrijven.

Ik snap trouwens niet helemaal waarvoor je het nodig hebt: Een O/R mapper maakt toch juist klassen op basis van een bestaande database? Of is wat jij maakt meer een 'Database Serializer'? :)

  • zoepercavia
  • Registratie: September 2001
  • Laatst online: 26-12-2025
Naar mijn weten kan een O/R mapper gewoon beide kanten op :) Oftewel een database maken op basis van een object-model, alswel een object model op basis van een database. Ik ben in ieder geval bezig met van object model naar database. "Mappen" klinkt in mijn oren ook meer als van object-model naar database.

Panacea.NL als je geinteresserd bent in IT en Geneeskunde!


  • dotcode
  • Registratie: Augustus 2003
  • Laatst online: 14-08 11:19

dotcode

///\00/\\

Structs vs. Classes
Structs may seem similar to classes, but there are important differences that you should be aware of. First of all, classes are reference types and structs are value types. By using structs, you can create objects that behave like the built-in types and enjoy their benefits as well.

Int32 zijn value types en dus structs.

Een oplossing voor je probleem kan zijn dat je een custom attribuut maakt die aangeeft dat het een class van je zelf is. Je kan natuurlijk veel meer leuke dingen doen, maar dit kan je hier mee oplossen. Als je voorbeeld code wilt hebben moet je maar effe mailen.

peter@objectadapter.nl

[ Voor 3% gewijzigd door dotcode op 21-08-2003 16:57 ]


  • EfBe
  • Registratie: Januari 2000
  • Niet online
zoepercavia schreef op 21 augustus 2003 @ 16:50:
Naar mijn weten kan een O/R mapper gewoon beide kanten op :) Oftewel een database maken op basis van een object-model, alswel een object model op basis van een database.
No way. Er zijn zoveel class hierarchien bedenkbaar die nooit en te nimmer 1:1 te creeeren zijn in puur DDL.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • Sjaaky
  • Registratie: Oktober 2000
  • Laatst online: 09:55
Als van een object van het type Type de properties IsValueType en IsAnsiClass true zijn, dan is het een struct.
Ik heb dit eigenlijk nergens in de docs teruggevonden, maar ook nog geen tegenvoorbeelden gezien.

edit:
Ok, klopt geen zak van (zeker dat IsAnsiClass niet). De reden dat het voor mij werkte, was dat ik zocht in de Types die gedefinieerd waren in een bepaalde assembly. Alle valuetypes daarin zijn structs. (eigenlijk zijn alle valuetypes, dus Int32, Double, etc.. te beschouwen als structs) :D

Tip: Voor dit soort dingen kan grasduinen in de .Net SDK documentatie (ook opgenomen in de MSDN) meer resultaat bieden dan zoeken op internet

[ Voor 58% gewijzigd door Sjaaky op 23-08-2003 16:13 ]


Verwijderd

Misschien eens naar wat voorbeelden kijken? ORM (www.olero.com) heeft een hele goeie Mapper en via de object browser kun je evt. zien hoe hun een en ander opgelost hebben?

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:56
In principe is een struct een C#-datastructuur; de CLI kent zelf geen "struct"-type. De C# struct wordt by default gemapped op een aggregate valuetype in de CLR, maar ik denk niet dat je de garantie hebt dat alle structs altijd value types zijn: ik kan me voorstellen dat de compiler bij wijze van optimalisatie structs boxed en dan zijn het opeens reference types geworden!

Het onderscheid tussen value types en reference types bestaat volgens mij dus uitsluitend in de CLR en volgt dus niet uit het gebruik van C# structs. Ik ken verder de reflection API van .NET niet, maar ik neem aan dat je de naam van het type op kan vragen; als je weet dat dat de naam van een struct is, dan ben je klaar. Zoniet, dan denk ik niet dat je op betrouwbare wijze structs van classes kunt onderscheiden (ze zijn voor de CLR namelijk hetzelfde ding), al kun je in de praktijk misschien een eind komen met de valuetype-heuristiek. Ik denk echter niet dat je daarmee kunt garanderen dat je code correct blijft werken, met een compiler die optimalisaties als by-reference passing voor constante argumenten en het vervangen van aggregates door meerdere scalars.

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Volgens de CLI standaard zijn structs altijd value types.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:56
EfBe schreef op 22 augustus 2003 @ 15:04:
Volgens de CLI standaard zijn structs altijd value types.
Volgens mij komt het woord struct helemaal niet in de CLI specificaties voor.

De C# specificatie spreek uitsluitend over value-type semantics en reference-type semantics. Structs kunnen wel degelijk geboxt worden (en dan zijn het dus reference types) wanneer ze bijvoorbeeld meegegeven aan een functie met een parameter van type object, wat per definitie een reference is.

Maar goed, ik begrijp het probleem van zoepercavia nog niet helemaal: hoe kom je aan de referentie naar je variabele die (mogelijk) een struct is? In het PDF document dat je aanhaalt wordt al duidelijk hoe ze daar onderscheid maken: door te checken op de attributen van het type. Een struct heeft blijkbaar de attributen sequential, sealed, wat een klasse niet heeft. Het gebruik van sequential geeft ook al aan dat het om een aggregate type gaat; een klasse kan nooit sealed zijn (of is er een C# equivalent van "Final"?).

[ Voor 23% gewijzigd door Soultaker op 22-08-2003 18:03 ]


  • zoepercavia
  • Registratie: September 2001
  • Laatst online: 26-12-2025
Fuck.. dubbelpost, mijn excuses voor mijne heren moderatoren

[ Voor 95% gewijzigd door zoepercavia op 22-08-2003 18:35 ]

Panacea.NL als je geinteresserd bent in IT en Geneeskunde!


  • zoepercavia
  • Registratie: September 2001
  • Laatst online: 26-12-2025
Soultaker schreef op 22 August 2003 @ 17:59:
[...]

Volgens mij komt het woord struct helemaal niet in de CLI specificaties voor.

De C# specificatie spreek uitsluitend over value-type semantics en reference-type semantics. Structs kunnen wel degelijk geboxt worden (en dan zijn het dus reference types) wanneer ze bijvoorbeeld meegegeven aan een functie met een parameter van type object, wat per definitie een reference is.

Maar goed, ik begrijp het probleem van zoepercavia nog niet helemaal: hoe kom je aan de referentie naar je variabele die (mogelijk) een struct is? In het PDF document dat je aanhaalt wordt al duidelijk hoe ze daar onderscheid maken: door te checken op de attributen van het type. Een struct heeft blijkbaar de attributen sequential, sealed, wat een klasse niet heeft. Het gebruik van sequential geeft ook al aan dat het om een aggregate type gaat; een klasse kan nooit sealed zijn (of is er een C# equivalent van "Final"?).
Mijn mapper generator scant een assembly op domein objecten (subklassen van DomainObject). Vervolgend wordt binnen het domein object gekeken naar properties. Als een property een struct is (daar heb je je referentie naar een variabele) dan moet hij dus naar meerdere kolommen gemapped worden (er vanuitgaande dat een struct meerdere velden bevat :)). Uiteindelijk heb ik het opgelost door een [PersistableAttribute] toe te voegen aan de type definitie van de struct.

Ik heb inderdaad naar Olero's ORM gekeken, en dat is ook een van mijn inspiratiebronnen geweest om een mapper te schrijven (naast Fowler en EfBe). Echter meer als leerstof om C# en het .Net Framework goed te leren kennen dan als iets echt bruikbaars. Ondertussen vind ik em wel bruikbaar genoeg voor mijn eigen projecten, vandaar ook de codegenerator (mapper code intypen neigt naar het onmogelijke).

Panacea.NL als je geinteresserd bent in IT en Geneeskunde!


  • Sjaaky
  • Registratie: Oktober 2000
  • Laatst online: 09:55
Soultaker schreef op 22 August 2003 @ 17:59:
[...]
De C# specificatie spreek uitsluitend over value-type semantics en reference-type semantics. Structs kunnen wel degelijk geboxt worden (en dan zijn het dus reference types) wanneer ze bijvoorbeeld meegegeven aan een functie met een parameter van type object, wat per definitie een reference is.
Structs kunnen geboxt worden, maar daar worden het nog geen refence-types van. Zou ook raar zijn de semantiek verschilt immers. Als je de specs voor je neus hebt zie 18.3.5. "A key difference from the same operations onclass types is that boxing and unboxing copies the struct value either into or out of the boxed instance.

.Net heeft structs omdat het bij goed gebruik performance verbeteringen kan geven tov het gebruik van classes.
Vergelijk de struct en class, in geheugengebruik en tijdsduur:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using System;
struct Complex_struct
{
    double im; double re;
}

struct Complex_class
{
    double im;double re;
}

class Test
{
    static void Main(string[] args)
    {
        TimeSpan start;
        start = DateTime.Now.TimeOfDay;
        Console.Out.WriteLine("start struct...");

        int amount =10000000;
        int i = 0;
        Complex_struct[] a = new Complex_struct[amount];
        for(i=0;i<amount;i++) 
        {
            a[i] = new Complex_struct();
        }
        Console.WriteLine("{0}",DateTime.Now.TimeOfDay-start);

        start = DateTime.Now.TimeOfDay;
        System.Console.Out.Write("start class...\n");
        Complex_class[] b = new Complex_class[amount];
        for(i=0;i<amount;i++) 
        {
            b[i] = new Complex_class();
        }
        Console.WriteLine("{0}",DateTime.Now.TimeOfDay-start);
        
    }
}


Als je veel objecten aanmaakt die geen inheritance etc nodig hebben, is een struct dus zeker het overwegen waard. Om hem als reference parameter mee te geven kan je het Foo( ref StructType Bar) gebruiken..

Overigens is het gebruik van een [PersistableAttribute] een stuk flexibeler aangezien je dan ook members in je class kan hebben, die niet in de db terecht hoeven komen.

[ Voor 3% gewijzigd door Sjaaky op 23-08-2003 16:17 ]


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:56
Ik ken het verschil tussen een struct en een class vanuit C# gezien, maar ook het verschil tussen value types en reference types voor de CLR. En nu zal ik jouw eens wat vertellen: je kunt bij het declareren van een type geen onderscheid maken tussen value types en reference types! Je kunt een C# object in de CLR dus prima als value type instantieren en een C# struct als reference type. Je moet er dan alleen voor waken dat de C# semantiek gewaarborgd blijft.

Mijn punt was en blijft dat het, voor zover ik weet, niet noodzakelijkerwijs zo is dat elke variabele die als C# type een struct heeft op CLR nivo een value type is. De .NET reflection API werkt op de CLI typen en spreekt dus de CLR aan. Hoewel het logisch is dat C# structs op een aantal plekken wel degelijk als value types gebruikt worden (als members van andere aggregate types, bijvoorbeeld), hoeft dat niet altijd voor zaken als variabelen, parameters, etcetera te gelden.

  • dotcode
  • Registratie: Augustus 2003
  • Laatst online: 14-08 11:19

dotcode

///\00/\\

Als je kijkt naar hoe ze zijn geimplementeerd is het logisch struct sneller zijn, een struct komt namelijk op de stack en een class op de heap. Als je new doet bij een struct is het memory al gealocceerd toen hij in de scoop kwam (of op een ander moment) en hoeft er geen memory allocatie meer gedaan te worden. Bij een class moet er op de heap worden gekeken naar een stukje memory en dat is veel duurder.

  • Sjaaky
  • Registratie: Oktober 2000
  • Laatst online: 09:55
@Soultaker: Ik zie je punt.

Als er nog mensen willen weten hoe je een struct kan (waarschijnlijk) herkennen:
code:
1
type.IsValueType && ! type.IsPrimitive)

  • TlighT
  • Registratie: Mei 2000
  • Laatst online: 22-03 10:40
Sjaaky schreef op 23 August 2003 @ 20:18:
@Soultaker: Ik zie je punt.

Als er nog mensen willen weten hoe je een struct kan (waarschijnlijk) herkennen:
code:
1
type.IsValueType && ! type.IsPrimitive)
Bovenstaande geldt dacht ik ook voor een Enum, die zou je dan ook moeten uitsluiten.

  • marcusk
  • Registratie: Februari 2001
  • Laatst online: 26-09-2023
Soultaker schreef op 23 augustus 2003 @ 18:25:
Mijn punt was en blijft dat het, voor zover ik weet, niet noodzakelijkerwijs zo is dat elke variabele die als C# type een struct heeft op CLR nivo een value type is. De .NET reflection API werkt op de CLI typen en spreekt dus de CLR aan. Hoewel het logisch is dat C# structs op een aantal plekken wel degelijk als value types gebruikt worden (als members van andere aggregate types, bijvoorbeeld), hoeft dat niet altijd voor zaken als variabelen, parameters, etcetera te gelden.
AFAIK moet je een CLR value-type zien als een value-type dat als het nodig is een reference-type wordt (bij het uitvoeren van een methode erop bv). Als je van een C# struct het type opvraagt zal het echter altijd als value-type aangegeven worden, onafhankelijk van of die specifieke instantie op de heap staat of op de stack.
dotcode schreef op 23 August 2003 @ 19:17:
Als je kijkt naar hoe ze zijn geimplementeerd is het logisch struct sneller zijn, een struct komt namelijk op de stack en een class op de heap. Als je new doet bij een struct is het memory al gealocceerd toen hij in de scoop kwam (of op een ander moment) en hoeft er geen memory allocatie meer gedaan te worden. Bij een class moet er op de heap worden gekeken naar een stukje memory en dat is veel duurder.
Snelheid is vaak nogal een ruim begrip, zo ook in dit geval :P De allocatie van een value-type is idd efficienter dan bij een ref-type, maar als je een struct doorgeeft als parameter moet het gekopieerd worden, wat juist duurder kan zijn als het type meer dan 32 bits groot is (op een 32 bits machine dan).

  • EfBe
  • Registratie: Januari 2000
  • Niet online
marcusk schreef op 24 August 2003 @ 01:12:
[...]

AFAIK moet je een CLR value-type zien als een value-type dat als het nodig is een reference-type wordt (bij het uitvoeren van een methode erop bv). Als je van een C# struct het type opvraagt zal het echter altijd als value-type aangegeven worden, onafhankelijk van of die specifieke instantie op de heap staat of op de stack.
Even een les vertalerbouw:
een value type wordt gealloceerd in het stackframe van de current scope, dus of in het stackframe van de huidige method/block of in het stackframe van de huidige instance of in de static instance in de huidige thread. Geef je een value type door op de normale manier aan een method, dan wordt de waarde gecopieerd. Geef je de value type via 'ref' door, dus een reference, dan geef je een REFERENCE door van het stukje geheugen in het STACKFRAME.

Je kunt nu via een ref parameter wel een private member dat een value type is, meegeven aan een method, en dus een addresspointer die wijst naar een heap adres meegeven, maar dat doet verder niet ter zake.

Een value type staat echter nooit op de heap zelf, het is altijd een onderdeel van een stackframe (simplistisch gezegd). Dat is ook de reden waarom structs sneller zijn in .NET: ze worden geallocceerd in het stackframe en dat kost weinig extra tijd. Dat ze op de stack staan is ook de reden waarom inmense structs nadelig zijn: je stack zit zo vol.
[...]
Snelheid is vaak nogal een ruim begrip, zo ook in dit geval :P De allocatie van een value-type is idd efficienter dan bij een ref-type, maar als je een struct doorgeeft als parameter moet het gekopieerd worden, wat juist duurder kan zijn als het type meer dan 32 bits groot is (op een 32 bits machine dan).
Dat lijkt me niet zo terzake doende. Tenslotte worden de parameters die je meegeeft aan een method ook weer op de stack geplaatst van de huidige thread, dus of die stackframe builder nu 4 of 8 bytes daarop moet zetten dat zal die routine echt niet merken. Op de Amiga was memcopy vroeger via de CPU al niet zo duur, op een normale moderne CPU lijkt me dat ook niet echt een probleem.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • marcusk
  • Registratie: Februari 2001
  • Laatst online: 26-09-2023
EfBe schreef op 24 augustus 2003 @ 10:32:
Even een les vertalerbouw:
Dat heb ik al gehad ;)
een value type wordt gealloceerd in het stackframe van de current scope, dus of in het stackframe van de huidige method/block of in het stackframe van de huidige instance of in de static instance in de huidige thread. Geef je een value type door op de normale manier aan een method, dan wordt de waarde gekopieerd. Geef je de value type via 'ref' door, dus een reference, dan geef je een REFERENCE door van het stukje geheugen in het STACKFRAME.
Dat klopt.
Je kunt nu via een ref parameter wel een private member dat een value type is, meegeven aan een method, en dus een addresspointer die wijst naar een heap adres meegeven, maar dat doet verder niet ter zake.
Agreed.
Een value type staat echter nooit op de heap zelf, het is altijd een onderdeel van een stackframe (simplistisch gezegd).
Misschien dat ik het niet zo duidelijk opgeschreven heb (niet meer posten met bier op ;)), maar mijn punt is nou juist dat CLR value-types wel degelijk op de stack kunnen staan, namelijk als ze geboxt zijn. Natuurlijk zijn het dan strict genomen ref-types, maar als je het type opvraagt zal het nog steeds als value-type aangegeven worden. Ik zie nu dat Sjaaky het eerder al wat duidelijker zei:
Structs kunnen geboxt worden, maar daar worden het nog geen refence-types van. Zou ook raar zijn de semantiek verschilt immers.
.
EfBe schreef:
Dat lijkt me niet zo terzake doende. Tenslotte worden de parameters die je meegeeft aan een method ook weer op de stack geplaatst van de huidige thread, dus of die stackframe builder nu 4 of 8 bytes daarop moet zetten dat zal die routine echt niet merken. Op de Amiga was memcopy vroeger via de CPU al niet zo duur, op een normale moderne CPU lijkt me dat ook niet echt een probleem.
dotcode zei in feite 'structs zijn sneller. punt.', net als jij hierboven zegt ('Dat is ook de reden waarom structs sneller zijn in .NET'). IMO is het niet zo simpel: denk maar aan de 'immense structs' waar je het zelf over hebt, die wel degelijk voor veel overhead zullen zorgen als ze steeds rondgekopieerd moeten worden.

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:56
marcusk schreef op 24 augustus 2003 @ 12:33:
Misschien dat ik het niet zo duidelijk opgeschreven heb (niet meer posten met bier op ;)), maar mijn punt is nou juist dat CLR value-types wel degelijk op de stack kunnen staan, namelijk als ze geboxt zijn.
Ik wil niet zeuren, maar je bedoelt hier waarschijnlijk heap in plaats van stack, neem ik aan? (Niet zoveel bier meer drinken ;).)

Maar ik wil zelfs verder gaan: als ik me niet vergis, kun je C# classes ook op de stack alloceren in de CLR!
Natuurlijk zijn het dan strict genomen ref-types, maar als je het type opvraagt zal het nog steeds als value-type aangegeven worden.
Ik blijf er bij dat een typedefinitie in de CLI weinig te maken heeft met de representatie daarvan in de CLR.
Pagina: 1