Algemeen typesysteem

Het algemene typesysteem definieert hoe typen worden gedeclareerd, gebruikt en beheerd in de algemene taalruntime en is ook een belangrijk onderdeel van de ondersteuning van de runtime voor integratie tussen talen. Het algemene typesysteem voert de volgende functies uit:

  • Hiermee stelt u een framework in waarmee u integratie in meerdere talen, typeveiligheid en krachtige code-uitvoering mogelijk maakt.

  • Biedt een objectgeoriënteerd model dat ondersteuning biedt voor de volledige implementatie van veel programmeertalen.

  • Definieert regels die talen moeten volgen, zodat objecten die in verschillende talen zijn geschreven, met elkaar kunnen communiceren.

  • Biedt een bibliotheek die de primitieve gegevenstypen (zoals Boolean, Byte, Charen Int32UInt64) bevat die worden gebruikt in de ontwikkeling van toepassingen.

Typen in .NET

Alle typen in .NET zijn waardetypen of verwijzingstypen.

Waardetypen zijn gegevenstypen waarvan de objecten worden vertegenwoordigd door de werkelijke waarde van het object. Als een exemplaar van een waardetype is toegewezen aan een variabele, krijgt die variabele een nieuwe kopie van de waarde.

Verwijzingstypen zijn gegevenstypen waarvan de objecten worden vertegenwoordigd door een verwijzing (vergelijkbaar met een aanwijzer) naar de werkelijke waarde van het object. Als een verwijzingstype is toegewezen aan een variabele, verwijst die variabele (verwijst naar) de oorspronkelijke waarde. Er is geen kopie gemaakt.

Het algemene typesysteem in .NET ondersteunt de volgende vijf categorieën typen:

Klassen

Een klasse is een verwijzingstype dat rechtstreeks kan worden afgeleid van een andere klasse en impliciet is afgeleid van System.Object. De klasse definieert de bewerkingen die een object (een exemplaar van de klasse) kan uitvoeren (methoden, gebeurtenissen of eigenschappen) en de gegevens die het object bevat (velden). Hoewel een klasse over het algemeen zowel definitie als implementatie omvat (in tegenstelling tot interfaces, die bijvoorbeeld alleen definitie zonder implementatie bevatten), kan deze een of meer leden hebben die geen implementatie hebben.

In de volgende tabel worden enkele van de kenmerken beschreven die een klasse mogelijk heeft. Elke taal die de runtime ondersteunt, biedt een manier om aan te geven dat een klasse of klasselid een of meer van deze kenmerken heeft. Afzonderlijke programmeertalen die zich richten op .NET, maken echter mogelijk niet al deze kenmerken beschikbaar.

Characteristic Beschrijving
Verzegeld Hiermee geeft u op dat een andere klasse niet kan worden afgeleid van dit type.
Implementeert Geeft aan dat de klasse een of meer interfaces gebruikt door implementaties van interfaceleden te bieden.
Abstract Geeft aan dat de klasse niet kan worden geïnstantieerd. Als u deze wilt gebruiken, moet u er een andere klasse aan afleiden.
Neemt Geeft aan dat exemplaren van de klasse kunnen worden gebruikt waar de basisklasse is opgegeven. Een afgeleide klasse die overneemt van een basisklasse kan gebruikmaken van de implementatie van openbare leden die door de basisklasse worden geleverd, of de afgeleide klasse kan de implementatie van de openbare leden overschrijven met een eigen implementatie.
geëxporteerd of niet geëxporteerd Hiermee wordt aangegeven of een klasse zichtbaar is buiten de assembly waarin deze is gedefinieerd. Dit kenmerk is alleen van toepassing op klassen op het hoogste niveau en niet op geneste klassen.

Notitie

Een klasse kan ook worden genest in een bovenliggende klasse of structuur. Geneste klassen hebben ook lidkenmerken. Zie Geneste typen voor meer informatie.

Klasseleden die geen implementatie hebben, zijn abstracte leden. Een klasse met een of meer abstracte leden is zelf abstract; er kunnen geen nieuwe exemplaren van worden gemaakt. In sommige talen waarop de runtime is gericht, kunt u een klasse markeren als abstract, zelfs als geen van de leden abstract is. U kunt een abstracte klasse gebruiken als u een basisset functionaliteit wilt inkapselen die afgeleide klassen kunnen overnemen of overschrijven wanneer dat van toepassing is. Klassen die niet abstract zijn, worden concrete klassen genoemd.

Een klasse kan een willekeurig aantal interfaces implementeren, maar kan ook worden overgenomen van slechts één basisklasse naast System.Object, waarvan alle klassen impliciet overnemen. Alle klassen moeten ten minste één constructor hebben, waarmee nieuwe exemplaren van de klasse worden geïnitialiseerd. Als u geen constructor expliciet definieert, bieden de meeste compilers automatisch een parameterloze constructor.

Structuren

Een structuur is een waardetype dat impliciet is afgeleid van System.ValueType, die op zijn beurt wordt afgeleid van System.Object. Een structuur is handig voor het weergeven van waarden waarvan de geheugenvereisten klein zijn en voor het doorgeven van waarden als by-value-parameters aan methoden met sterk getypte parameters. In .NET worden alle primitieve gegevenstypen (Boolean, Byte, Char, DateTime, , Decimal, Double, Int32SByteSingleInt64Int16, , UInt16, UInt32en UInt64) gedefinieerd als structuren.

Net als klassen definiëren structuren zowel gegevens (de velden van de structuur) als de bewerkingen die op die gegevens kunnen worden uitgevoerd (de methoden van de structuur). Dit betekent dat u methoden voor structuren kunt aanroepen, inclusief de virtuele methoden die zijn gedefinieerd voor de System.Object en System.ValueType klassen, en alle methoden die zijn gedefinieerd voor het waardetype zelf. Met andere woorden, structuren kunnen velden, eigenschappen en gebeurtenissen bevatten, evenals statische en niet-statische methoden. U kunt instanties van structuren maken, deze doorgeven als parameters, ze opslaan als lokale variabelen of opslaan in een veld van een ander waardetype of verwijzingstype. Structuren kunnen ook interfaces implementeren.

Waardetypen verschillen ook van klassen in verschillende opzichten. Ten eerste, hoewel ze impliciet overnemen van System.ValueType, kunnen ze niet rechtstreeks overnemen van elk type. Op dezelfde manier worden alle waardetypen verzegeld, wat betekent dat er geen ander type kan worden afgeleid. Ze hebben ook geen constructors nodig.

Voor elk waardetype levert de algemene taalruntime een bijbehorend type, een klasse met dezelfde status en hetzelfde gedrag als het waardetype. Een exemplaar van een waardetype wordt in een vak geplaatst wanneer deze wordt doorgegeven aan een methode die een parameter van het type System.Objectaccepteert. Het wordt niet in het postvak (dat wil gezegd, geconverteerd van een exemplaar van een klasse terug naar een exemplaar van een waardetype) wanneer het besturingselement wordt geretourneerd vanuit een methodeaanroep die een waardetype accepteert als een by-reference-parameter. Voor sommige talen is vereist dat u speciale syntaxis gebruikt wanneer het vaktype vereist is; anderen gebruiken automatisch het vakkentype wanneer dit nodig is. Wanneer u een waardetype definieert, definieert u zowel het vak als het niet-boxed type.

Opsommingen

Een opsomming is een waardetype dat rechtstreeks wordt overgenomen van System.Enum en die alternatieve namen levert voor de waarden van een onderliggend primitief type. Een opsommingstype heeft een naam, een onderliggend type dat een van de ingebouwde typen ondertekende of niet-ondertekende gehele getallen (zoals ByteInt32, of UInt64) en een set velden moet zijn. De velden zijn statische letterlijke velden, die elk een constante vertegenwoordigen. Dezelfde waarde kan worden toegewezen aan meerdere velden. Wanneer dit gebeurt, moet u een van de waarden markeren als de primaire opsommingswaarde voor weerspiegeling en tekenreeksconversie.

U kunt een waarde van het onderliggende type toewijzen aan een opsomming en omgekeerd (er is geen cast vereist voor de runtime). U kunt een exemplaar van een opsomming maken en de methoden van System.Enum, evenals methoden die zijn gedefinieerd op het onderliggende type van de opsomming, aanroepen. In sommige talen kunt u echter geen opsomming doorgeven als parameter wanneer een exemplaar van het onderliggende type vereist is (of omgekeerd).

De volgende aanvullende beperkingen zijn van toepassing op opsommingen:

  • Ze kunnen hun eigen methoden niet definiëren.

  • Ze kunnen geen interfaces implementeren.

  • Ze kunnen geen eigenschappen of gebeurtenissen definiëren.

  • Ze kunnen niet algemeen zijn, tenzij ze alleen algemeen zijn omdat ze zijn genest binnen een algemeen type. Dat wil zeggen dat een opsomming geen eigen typeparameters kan hebben.

    Notitie

    Geneste typen (inclusief opsommingen) die zijn gemaakt met Visual Basic, C# en C++ bevatten de typeparameters van alle algemene typen en zijn daarom algemeen, zelfs als ze geen typeparameters hebben. Zie 'Geneste typen' in het Type.MakeGenericType naslagonderwerp voor meer informatie.

Het FlagsAttribute kenmerk geeft een speciaal soort opsomming aan die een bitveld wordt genoemd. De runtime zelf maakt geen onderscheid tussen traditionele opsommingen en bitvelden, maar uw taal kan dit wel doen. Wanneer dit onderscheid wordt gemaakt, kunnen bitsgewijze operatoren worden gebruikt voor bitvelden, maar niet voor opsommingen, om niet-benoemde waarden te genereren. Opsommingen worden over het algemeen gebruikt voor lijsten met unieke elementen, zoals dagen van de week, land- of regionamen, enzovoort. Bitvelden worden over het algemeen gebruikt voor lijsten met kwaliteiten of hoeveelheden die in combinatie kunnen optreden, zoals Red And Big And Fast.

In het volgende voorbeeld ziet u hoe u zowel bitvelden als traditionele opsommingen gebruikt.

using System;
using System.Collections.Generic;

// A traditional enumeration of some root vegetables.
public enum SomeRootVegetables
{
    HorseRadish,
    Radish,
    Turnip
}

// A bit field or flag enumeration of harvesting seasons.
[Flags]
public enum Seasons
{
    None = 0,
    Summer = 1,
    Autumn = 2,
    Winter = 4,
    Spring = 8,
    All = Summer | Autumn | Winter | Spring
}

public class Example
{
   public static void Main()
   {
       // Hash table of when vegetables are available.
       Dictionary<SomeRootVegetables, Seasons> AvailableIn = new Dictionary<SomeRootVegetables, Seasons>();

       AvailableIn[SomeRootVegetables.HorseRadish] = Seasons.All;
       AvailableIn[SomeRootVegetables.Radish] = Seasons.Spring;
       AvailableIn[SomeRootVegetables.Turnip] = Seasons.Spring |
            Seasons.Autumn;

       // Array of the seasons, using the enumeration.
       Seasons[] theSeasons = new Seasons[] { Seasons.Summer, Seasons.Autumn,
            Seasons.Winter, Seasons.Spring };

       // Print information of what vegetables are available each season.
       foreach (Seasons season in theSeasons)
       {
          Console.Write(String.Format(
              "The following root vegetables are harvested in {0}:\n",
              season.ToString("G")));
          foreach (KeyValuePair<SomeRootVegetables, Seasons> item in AvailableIn)
          {
             // A bitwise comparison.
             if (((Seasons)item.Value & season) > 0)
                 Console.Write(String.Format("  {0:G}\n",
                      (SomeRootVegetables)item.Key));
          }
       }
   }
}
// The example displays the following output:
//    The following root vegetables are harvested in Summer:
//      HorseRadish
//    The following root vegetables are harvested in Autumn:
//      Turnip
//      HorseRadish
//    The following root vegetables are harvested in Winter:
//      HorseRadish
//    The following root vegetables are harvested in Spring:
//      Turnip
//      Radish
//      HorseRadish
Imports System.Collections.Generic

' A traditional enumeration of some root vegetables.
Public Enum SomeRootVegetables
    HorseRadish
    Radish
    Turnip
End Enum

' A bit field or flag enumeration of harvesting seasons.
<Flags()> Public Enum Seasons
    None = 0
    Summer = 1
    Autumn = 2
    Winter = 4
    Spring = 8
    All = Summer Or Autumn Or Winter Or Spring
End Enum

' Entry point.
Public Class Example
    Public Shared Sub Main()
        ' Hash table of when vegetables are available.
        Dim AvailableIn As New Dictionary(Of SomeRootVegetables, Seasons)()

        AvailableIn(SomeRootVegetables.HorseRadish) = Seasons.All
        AvailableIn(SomeRootVegetables.Radish) = Seasons.Spring
        AvailableIn(SomeRootVegetables.Turnip) = Seasons.Spring Or _
                                                 Seasons.Autumn

        ' Array of the seasons, using the enumeration.
        Dim theSeasons() As Seasons = {Seasons.Summer, Seasons.Autumn, _
                                       Seasons.Winter, Seasons.Spring}

        ' Print information of what vegetables are available each season.
        For Each season As Seasons In theSeasons
            Console.WriteLine(String.Format( _
                 "The following root vegetables are harvested in {0}:", _
                 season.ToString("G")))
            For Each item As KeyValuePair(Of SomeRootVegetables, Seasons) In AvailableIn
                ' A bitwise comparison.
                If (CType(item.Value, Seasons) And season) > 0 Then
                    Console.WriteLine("  " + _
                          CType(item.Key, SomeRootVegetables).ToString("G"))
                End If
            Next
        Next
    End Sub
End Class
' The example displays the following output:
'    The following root vegetables are harvested in Summer:
'      HorseRadish
'    The following root vegetables are harvested in Autumn:
'      Turnip
'      HorseRadish
'    The following root vegetables are harvested in Winter:
'      HorseRadish
'    The following root vegetables are harvested in Spring:
'      Turnip
'      Radish
'      HorseRadish

Interfaces

Een interface definieert een contract dat een 'can do'-relatie of een 'has a'-relatie aangeeft. Interfaces worden vaak gebruikt om functionaliteit te implementeren, zoals het vergelijken en sorteren (de IComparable en IComparable<T> interfaces), testen op gelijkheid (de IEquatable<T> interface) of het inventariseren van items in een verzameling (de IEnumerable en IEnumerable<T> interfaces). Interfaces kunnen eigenschappen, methoden en gebeurtenissen hebben, die allemaal abstracte leden zijn; Dat wil gezegd, hoewel de interface de leden en hun handtekeningen definieert, blijft deze over aan het type dat de interface implementeert om de functionaliteit van elk interfacelid te definiëren. Dit betekent dat elke klasse of structuur die een interface implementeert definities moet leveren voor de abstracte leden die in de interface zijn gedeclareerd. Een interface kan elke implementatieklasse of structuur vereisen om ook een of meer andere interfaces te implementeren.

De volgende beperkingen gelden voor interfaces:

  • Een interface kan worden gedeclareerd met elke toegankelijkheid, maar interfaceleden moeten allemaal openbare toegankelijkheid hebben.
  • Interfaces kunnen geen constructors definiëren.
  • Interfaces kunnen geen velden definiëren.
  • Interfaces kunnen alleen exemplaarleden definiëren. Ze kunnen geen statische leden definiëren.

Elke taal moet regels opgeven voor het toewijzen van een implementatie aan de interface waarvoor het lid is vereist, omdat meer dan één interface een lid met dezelfde handtekening kan declareren en deze leden afzonderlijke implementaties kunnen hebben.

Gedelegeerden

Gemachtigden zijn referentietypen die vergelijkbaar zijn met die van functie-aanwijzers in C++. Ze worden gebruikt voor gebeurtenis-handlers en callback-functies in .NET. In tegenstelling tot functiepointers zijn gemachtigden veilig, verifieerbaar en typen ze veilig. Een gemachtigdentype kan elke instantiemethode of statische methode met een compatibele handtekening vertegenwoordigen.

Een parameter van een gemachtigde is compatibel met de bijbehorende parameter van een methode als het type van de gemachtigde parameter meer beperkend is dan het type methodeparameter, omdat dit garandeert dat een argument dat wordt doorgegeven aan de gemachtigde veilig aan de methode kan worden doorgegeven.

Op dezelfde manier is het retourtype van een gemachtigde compatibel met het retourtype van een methode als het retourtype van de methode meer beperkend is dan het retourtype van de gemachtigde, omdat dit garandeert dat de retourwaarde van de methode veilig kan worden gecast naar het retourtype van de gemachtigde.

Een gemachtigde met een parameter van het type IEnumerable en een retourtype Object kan bijvoorbeeld een methode vertegenwoordigen met een parameter van het type Object en een retourwaarde van het type IEnumerable. Zie voor meer informatie en voorbeeldcode Delegate.CreateDelegate(Type, Object, MethodInfo).

Een gemachtigde wordt geacht gebonden te zijn aan de methode die deze vertegenwoordigt. Naast dat deze is gebonden aan de methode, kan een gemachtigde worden gebonden aan een object. Het object vertegenwoordigt de eerste parameter van de methode en wordt telkens wanneer de gemachtigde wordt aangeroepen, doorgegeven aan de methode. Als de methode een instantiemethode is, wordt het afhankelijke object doorgegeven als de impliciete this parameter (Me in Visual Basic). Als de methode statisch is, wordt het object doorgegeven als de eerste formele parameter van de methode en moet de handtekening van de gemachtigde overeenkomen met de resterende parameters. Zie voor meer informatie en voorbeeldcode System.Delegate.

Alle gemachtigden nemen over van System.MulticastDelegate, die overnemen van System.Delegate. De talen C#, Visual Basic en C++ staan overname van deze typen niet toe. In plaats daarvan bieden ze trefwoorden voor het declareren van gemachtigden.

Omdat gemachtigden overnemen van MulticastDelegate, heeft een gemachtigde een aanroeplijst. Dit is een lijst met methoden die de gemachtigde vertegenwoordigt en die worden uitgevoerd wanneer de gemachtigde wordt aangeroepen. Alle methoden in de lijst ontvangen de argumenten die worden opgegeven wanneer de gemachtigde wordt aangeroepen.

Notitie

De retourwaarde is niet gedefinieerd voor een gemachtigde met meer dan één methode in de aanroeplijst, zelfs niet als de gemachtigde een retourtype heeft.

In veel gevallen, zoals bij callback-methoden, vertegenwoordigt een gemachtigde slechts één methode en de enige acties die u moet uitvoeren, zijn het maken van de gemachtigde en het aanroepen ervan.

Voor gemachtigden die meerdere methoden vertegenwoordigen, biedt .NET methoden van de Delegate en MulticastDelegate gedelegeerdenklassen om bewerkingen te ondersteunen, zoals het toevoegen van een methode aan de aanroeplijst van een gemachtigde (de Delegate.Combine methode), het verwijderen van een methode (de Delegate.Remove methode) en het ophalen van de aanroeplijst (de Delegate.GetInvocationList methode).

Notitie

Het is niet nodig om deze methoden te gebruiken voor gebeurtenis-handler-gemachtigden in C#, C++en Visual Basic, omdat deze talen syntaxis bieden voor het toevoegen en verwijderen van gebeurtenis-handlers.

Typedefinities

Een typedefinitie bevat het volgende:

  • Alle kenmerken die zijn gedefinieerd voor het type.
  • De toegankelijkheid van het type (zichtbaarheid).
  • De naam van het type.
  • Het basistype van het type.
  • Alle interfaces die door het type zijn geïmplementeerd.
  • Definities voor elk van de leden van het type.

Kenmerken

Kenmerken bieden aanvullende door de gebruiker gedefinieerde metagegevens. Meestal worden ze gebruikt voor het opslaan van aanvullende informatie over een type in de assembly of voor het wijzigen van het gedrag van een typelid in de ontwerp- of runtimeomgeving.

Kenmerken zijn zelf klassen die overnemen van System.Attribute. Talen die het gebruik van kenmerken ondersteunen, hebben elk hun eigen syntaxis voor het toepassen van kenmerken op een taalelement. Kenmerken kunnen worden toegepast op vrijwel elk taalelement; de specifieke elementen waarop een kenmerk kan worden toegepast, worden gedefinieerd door de AttributeUsageAttribute elementen die op die kenmerkklasse worden toegepast.

Type toegankelijkheid

Alle typen hebben een wijzigingsfunctie die de toegankelijkheid van andere typen regelt. In de volgende tabel worden de typen toegankelijkheid beschreven die worden ondersteund door de runtime.

Toegankelijkheid Beschrijving
openbaar Het type is toegankelijk voor alle assembly's.
assembly Het type is alleen toegankelijk vanuit de assembly.

De toegankelijkheid van een genest type is afhankelijk van het toegankelijkheidsdomein, dat wordt bepaald door zowel de gedeclareerde toegankelijkheid van het lid als het toegankelijkheidsdomein van het onmiddellijk met het betreffende type. Het toegankelijkheidsdomein van een genest type mag echter niet groter zijn dan het type dat het bevat.

Het toegankelijkheidsdomein van een geneste lid M dat is gedeclareerd in een type T binnen een programma P , wordt als volgt gedefinieerd (notatie die M mogelijk zelf een type is):

  • Als de gedeclareerde toegankelijkheid M is public, is het toegankelijkheidsdomein MTvan .

  • Als de gedeclareerde toegankelijkheid M is protected internal, is het toegankelijkheidsdomein M het snijpunt van het toegankelijkheidsdomein van T met de programmatekst van P en de programmatekst van elk type dat is afgeleid van T buiten Pgedeclareerd.

  • Als de gedeclareerde toegankelijkheid M is protected, is het toegankelijkheidsdomein M het snijpunt van het toegankelijkheidsdomein van T met de programmatekst van T en elk type dat is afgeleid van T.

  • Als de gedeclareerde toegankelijkheid M is internal, is het toegankelijkheidsdomein M het snijpunt van het toegankelijkheidsdomein van T met de programmatekst van P.

  • Als de gedeclareerde toegankelijkheid M is private, is het toegankelijkheidsdomein M de programmatekst van T.

Typ namen

Het algemene typesysteem legt slechts twee beperkingen op voor namen:

  • Alle namen worden gecodeerd als tekenreeksen met Unicode-tekens (16-bits).
  • Namen mogen geen ingesloten (16-bits) waarde van 0x0000 hebben.

In de meeste talen gelden echter extra beperkingen voor typenamen. Alle vergelijkingen worden op basis van byte-byte uitgevoerd en zijn daarom hoofdlettergevoelig en landinstellingenonafhankelijk.

Hoewel een type kan verwijzen naar typen uit andere modules en assembly's, moet een type volledig zijn gedefinieerd binnen één .NET-module. (Afhankelijk van de compilerondersteuning kan deze echter worden onderverdeeld in meerdere broncodebestanden.) Typenamen hoeven alleen uniek te zijn binnen een naamruimte. Als u een type volledig wilt identificeren, moet de typenaam worden gekwalificeerd door de naamruimte die de implementatie van het type bevat.

Basistypen en interfaces

Een type kan waarden en gedrag overnemen van een ander type. Het algemene typesysteem staat niet toe dat typen overnemen van meer dan één basistype.

Een type kan een willekeurig aantal interfaces implementeren. Als u een interface wilt implementeren, moet een type alle virtuele leden van die interface implementeren. Een virtuele methode kan worden geïmplementeerd door een afgeleid type en kan statisch of dynamisch worden aangeroepen.

Leden typen

Met de runtime kunt u leden van uw type definiëren, waarmee het gedrag en de status van een type worden opgegeven. Type leden zijn onder andere:

Velden

Een veld beschrijft en bevat een deel van de status van het type. Velden kunnen van elk type zijn dat door de runtime wordt ondersteund. Meestal zijn velden ofwel private of protected, zodat ze alleen toegankelijk zijn vanuit de klasse of van een afgeleide klasse. Als de waarde van een veld kan worden gewijzigd van buiten het type, wordt doorgaans een eigenschapsset accessor gebruikt. Openbaar weergegeven velden zijn meestal alleen-lezen en kunnen van twee typen zijn:

  • Constanten, waarvan de waarde tijdens het ontwerptijd wordt toegewezen. Dit zijn statische leden van een klasse, hoewel ze niet zijn gedefinieerd met het static trefwoord (Shared in Visual Basic).
  • Variabelen met het kenmerk Alleen-lezen, waarvan de waarden kunnen worden toegewezen in de klasseconstructor.

In het volgende voorbeeld ziet u deze twee gebruiksgegevens van alleen-lezenvelden.

using System;

public class Constants
{
   public const double Pi = 3.1416;
   public readonly DateTime BirthDate;

   public Constants(DateTime birthDate)
   {
      this.BirthDate = birthDate;
   }
}

public class Example
{
   public static void Main()
   {
      Constants con = new Constants(new DateTime(1974, 8, 18));
      Console.Write(Constants.Pi + "\n");
      Console.Write(con.BirthDate.ToString("d") + "\n");
   }
}
// The example displays the following output if run on a system whose current
// culture is en-US:
//    3.1416
//    8/18/1974
Public Class Constants
    Public Const Pi As Double = 3.1416
    Public ReadOnly BirthDate As Date

    Public Sub New(birthDate As Date)
        Me.BirthDate = birthDate
    End Sub
End Class

Public Module Example
    Public Sub Main()
        Dim con As New Constants(#8/18/1974#)
        Console.WriteLine(Constants.Pi.ToString())
        Console.WriteLine(con.BirthDate.ToString("d"))
    End Sub
End Module
' The example displays the following output if run on a system whose current
' culture is en-US:
'    3.1416
'    8/18/1974

Eigenschappen

Een eigenschap noemt een waarde of status van het type en definieert methoden voor het ophalen of instellen van de waarde van de eigenschap. Eigenschappen kunnen primitieve typen zijn, verzamelingen primitieve typen, door de gebruiker gedefinieerde typen of verzamelingen van door de gebruiker gedefinieerde typen. Eigenschappen worden vaak gebruikt om de openbare interface van een type onafhankelijk te houden van de werkelijke weergave van het type. Hierdoor kunnen eigenschappen waarden weergeven die niet rechtstreeks in de klasse zijn opgeslagen (bijvoorbeeld wanneer een eigenschap een berekende waarde retourneert) of validatie uitvoeren voordat waarden worden toegewezen aan privévelden. In het volgende voorbeeld ziet u het laatste patroon.

using System;

public class Person
{
   private int m_Age;

   public int Age
   {
      get { return m_Age; }
      set {
         if (value < 0 || value > 125)
         {
            throw new ArgumentOutOfRangeException("The value of the Age property must be between 0 and 125.");
         }
         else
         {
            m_Age = value;
         }
      }
   }
}
Public Class Person
    Private m_Age As Integer

    Public Property Age As Integer
        Get
            Return m_Age
        End Get
        Set
            If value < 0 Or value > 125 Then
                Throw New ArgumentOutOfRangeException("The value of the Age property must be between 0 and 125.")
            Else
                m_Age = value
            End If
        End Set
    End Property
End Class

Naast het opnemen van de eigenschap zelf, bevat de gemeenschappelijke tussentaal (CIL) voor een type dat een leesbare eigenschap bevat een get_eigenschapsnaammethode en bevat de CIL voor een type dat een beschrijfbare eigenschap bevat een set_eigenschapsnaammethode .

Methoden

In een methode worden bewerkingen beschreven die beschikbaar zijn voor het type. De handtekening van een methode geeft de toegestane typen van alle parameters en van de retourwaarde aan.

Hoewel de meeste methoden het exacte aantal parameters definiëren dat is vereist voor methode-aanroepen, ondersteunen sommige methoden een variabel aantal parameters. De laatste gedeclareerde parameter van deze methoden wordt gemarkeerd met het ParamArrayAttribute kenmerk. Taalcompilers bieden doorgaans een trefwoord, zoals params in C# en ParamArray visual Basic, waardoor expliciet gebruik wordtgemaakt van ParamArrayAttribute onnodig.

Constructors

Een constructor is een speciaal soort methode waarmee nieuwe exemplaren van een klasse of structuur worden gemaakt. Net als bij elke andere methode kan een constructor parameters bevatten; constructors hebben echter geen retourwaarde (dat wil gezegd, ze retourneren void).

Als de broncode voor een klasse geen constructor expliciet definieert, bevat de compiler een parameterloze constructor. Als de broncode voor een klasse echter alleen geparameteriseerde constructors definieert, genereren de Visual Basic- en C#-compilers geen constructor zonder parameters.

Als de broncode voor een structuur constructors definieert, moeten ze worden geparameteriseerd; een structuur kan geen parameterloze constructor definiëren en compilers genereren geen parameterloze constructors voor structuren of andere waardetypen. Alle waardetypen hebben een impliciete constructor zonder parameters. Deze constructor wordt geïmplementeerd door de algemene taalruntime en initialiseert alle velden van de structuur naar hun standaardwaarden.

gebeurtenis

Een gebeurtenis definieert een incident waarop kan worden gereageerd en definieert methoden voor het abonneren op, het afmelden van en het opheffen van de gebeurtenis. Gebeurtenissen worden vaak gebruikt om andere typen statuswijzigingen te informeren. Zie Gebeurtenissen voor meer informatie.

Geneste typen

Een genest type is een type dat lid is van een ander type. Geneste typen moeten nauw zijn gekoppeld aan het bijbehorende type en mogen niet nuttig zijn als algemeen type. Geneste typen zijn handig wanneer het declaratietype exemplaren van het geneste type gebruikt en maakt, en het gebruik van het geneste type wordt niet weergegeven in openbare leden.

Geneste typen zijn verwarrend voor sommige ontwikkelaars en mogen niet openbaar zichtbaar zijn, tenzij er een overtuigende reden voor zichtbaarheid is. In een goed ontworpen bibliotheek moeten ontwikkelaars zelden geneste typen gebruiken om objecten te instantiëren of variabelen te declareren.

Kenmerken van typeleden

Met het algemene typesysteem kunnen typeleden verschillende kenmerken hebben; talen zijn echter niet vereist om al deze kenmerken te ondersteunen. In de volgende tabel worden lidkenmerken beschreven.

Characteristic Kan van toepassing zijn op Beschrijving
Abstract Methoden, eigenschappen en gebeurtenissen Het type levert de implementatie van de methode niet op. Typen die abstracte methoden overnemen of implementeren, moeten een implementatie voor de methode leveren. De enige uitzondering hierop is wanneer het afgeleide type zichzelf een abstract type is. Alle abstracte methoden zijn virtueel.
privé, familie, assembly, familie en assembly, familie of assembly, of openbaar Alle Definieert de toegankelijkheid van het lid:

privé
Alleen toegankelijk vanuit hetzelfde type als het lid of binnen een genest type.

family
Toegankelijk vanuit hetzelfde type als het lid en van afgeleide typen die hiervan overnemen.

assembly
Alleen toegankelijk in de assembly waarin het type is gedefinieerd.

familie en assembly
Alleen toegankelijk vanaf typen die in aanmerking komen voor zowel gezins- als assemblytoegang.

familie of assembly
Alleen toegankelijk vanaf typen die in aanmerking komen voor gezins- of assemblytoegang.

openbaar
Toegankelijk vanaf elk type.
Definitieve Methoden, eigenschappen en gebeurtenissen De virtuele methode kan niet worden overschreven in een afgeleid type.
alleen initialiseren Velden De waarde kan alleen worden geïnitialiseerd en kan niet worden geschreven na initialisatie.
instance Velden, methoden, eigenschappen en gebeurtenissen Als een lid niet is gemarkeerd als static (C# en C++), Shared (Visual Basic), virtual (C# en C++) of Overridable (Visual Basic), is het een exemplaarlid (er is geen trefwoord voor het exemplaar). Er zijn zoveel kopieën van dergelijke leden in het geheugen als er objecten zijn die deze gebruiken.
Letterlijke Velden De waarde die aan het veld is toegewezen, is een vaste waarde, bekend tijdens het compileren, van een ingebouwd waardetype. Letterlijke velden worden soms constanten genoemd.
newslot of overschrijven Alle Hiermee definieert u hoe het lid communiceert met overgenomen leden met dezelfde handtekening:

newslot
Hiermee worden overgenomen leden verborgen die dezelfde handtekening hebben.

overschrijven
Vervangt de definitie van een overgenomen virtuele methode.

De standaardwaarde is newslot.
statisch Velden, methoden, eigenschappen en gebeurtenissen Het lid behoort tot het type waarop het is gedefinieerd, niet tot een bepaald exemplaar van het type; het lid bestaat zelfs als er geen exemplaar van het type wordt gemaakt en het wordt gedeeld tussen alle exemplaren van het type.
Virtuele Methoden, eigenschappen en gebeurtenissen De methode kan worden geïmplementeerd door een afgeleid type en kan statisch of dynamisch worden aangeroepen. Als dynamische aanroep wordt gebruikt, bepaalt het type exemplaar dat de aanroep uitvoert (in plaats van het type dat bekend is tijdens het compileren) welke implementatie van de methode wordt aangeroepen. Als u een virtuele methode statisch wilt aanroepen, moet de variabele mogelijk worden gecast naar een type dat gebruikmaakt van de gewenste versie van de methode.

Overbelasting

Elk typelid heeft een unieke handtekening. Methodehandtekeningen bestaan uit de naam van de methode en een parameterlijst (de volgorde en typen argumenten van de methode). Er kunnen meerdere methoden met dezelfde naam worden gedefinieerd binnen een type zolang hun handtekeningen verschillen. Wanneer twee of meer methoden met dezelfde naam zijn gedefinieerd, wordt gezegd dat de methode overbelast is. In dit System.Charvoorbeeld is de IsDigit methode overbelast. Eén methode neemt een Char. De andere methode neemt een String en een Int32.

Notitie

Het retourtype wordt niet beschouwd als onderdeel van de handtekening van een methode. Dat wil gezegd, methoden kunnen niet worden overbelast als ze alleen per retourtype verschillen.

Leden overnemen, overschrijven en verbergen

Een afgeleid type neemt alle leden van het basistype over; dat wil gezegd dat deze leden zijn gedefinieerd op en beschikbaar zijn voor het afgeleide type. Het gedrag of de kwaliteiten van overgenomen leden kunnen op twee manieren worden gewijzigd:

  • Een afgeleid type kan een overgenomen lid verbergen door een nieuw lid met dezelfde handtekening te definiëren. Dit kan worden gedaan om een eerder openbaar lid privé te maken of om nieuw gedrag te definiëren voor een overgenomen methode die is gemarkeerd als final.

  • Een afgeleid type kan een overgenomen virtuele methode overschrijven. De onderdrukkingsmethode biedt een nieuwe definitie van de methode die wordt aangeroepen op basis van het type van de waarde tijdens runtime in plaats van het type variabele dat bekend is tijdens het compileren. Een methode kan een virtuele methode alleen overschrijven als de virtuele methode niet is gemarkeerd als final en de nieuwe methode minstens zo toegankelijk is als de virtuele methode.

Zie ook