Benutzer mit den meisten Antworten
<VBFixedArray> scheint nicht (mehr) zu funktionieren ...

Frage
-
Ich definiere eine STruktur mit einem 8-Byte grosse Byte-Array ..
Structure CANRawMsg ''' <summary> ''' Gibt den CAN-Identifier wieder. Entweder 29-Bit (CAN2.0B) oder 11-Bit (CAN2.0A)lang ''' </summary> ''' <remarks>derzeit repräsentieren die Bits 31 und 30 extended, rsp. remote Nachrichten</remarks> Public CANID As UInt32 ''' <summary> ''' Data length code - Anzahl der Nutzbytes ''' </summary> ''' <remarks>Erlaubt sind Zahlen zwischen 0 und 8</remarks> Public DLC As Byte ''' <summary> ''' Die eigentlichen Nutzdaten der Nachricht ''' </summary> ''' <remarks>Es sind zwischen 0 und 8 Byte Nutzdaten vorgesehen</remarks> <MarshalAs(UnmanagedType.ByValArray, SizeConst:=8)> _ Public Data() As Byte ''' <summary> ''' enthält nähere Angaben zur Art des Paketes ''' </summary> ''' <remarks></remarks> Public PacketType As PacketType ''' <summary> ''' gibt an, ob es sich bei dem Paket um ein CAN 2.0A oder 2.0B-Paket handelt ''' </summary> ''' <remarks>Diese Angabe sollte eigentlich später nicht mehr erforderlich sein und unterbleiben!</remarks> Public Extended As FrameType Public Remote As Boolean End Structure
Problematisch ist die Zeile mit <Marshal... Zuvor habe ich <VBFixedArray> verwendet.
In meinem Testcode wird nun folgender Code verwandt:
Dim testmsg As CAN2USB.CAN2USB.CANRawMsg, i As UInt16 With testmsg ReDim .Data(7) .Extended = CAN2USB.CAN2USB.FrameType.CAN20B .PacketType = CAN2USB.CAN2USB.PacketType.UART_Test .Data(0) = 0 .Data(1) = 1 .Remote = False End With
Lasse ich die Redim-Anweisung weg, dann erhalte ich eine NullReference-Exception beim Zugriff auf Data(0).
Mir scheint der Versuch, das Array fest auf eine Grösse von 8 Byte zu setzen bleibt wirkunglos.
Warum ?
Antworten
-
Hallo Nico,
Problematisch ist die Zeile mit <Marshal... Zuvor habe ich <VBFixedArray> verwendet.
.NET unterstützt keine Arrays mit festen Längen. VBFixedArray bzw. MarshalAs sind nur in InterOp Szenarien von Bedeutung. Hier übernimmt die Runtime dann die entsprechende Dimensionierung und Übergabe. Somit bleibt nur die Möglichkeit das Array zuvor über die ReDim Anweisung zu dimensionieren.
Thorsten Dörfler
Microsoft MVP Visual Basic
vb-faq.de- Als Antwort markiert Thorsten DörflerModerator Samstag, 31. Juli 2010 15:46
-
Hallo Nico,
Auch für VBFixedArray gilt schon:[VBFixedArrayAttribute-Klasse (Microsoft.VisualBasic)]
http://msdn.microsoft.com/de-de/library/microsoft.visualbasic.vbfixedarrayattribute.aspxVBFixedArrayAttribute dient lediglich der Information und reserviert keinen Speicher. Es verändert die Verwendung von Arrays in Strukturen und nicht lokalen Variablen durch Methoden oder API-Aufrufe, die VBFixedArrayAttribute erkennen. Beachten Sie, dass dieses Attribut kein Array mit variabler Länge in ein Array fester Länge umwandelt, und dass Sie mithilfe der Dim-Anweisung oder der ReDim-Anweisung Arrayspeicher zuordnen müssen.
_____________________Nur beiläufig erwähnt ... es gäbe unter .NET zum Beispiel: [Puffer fester Größe (C#-Programmierhandbuch)]
http://msdn.microsoft.com/de-de/library/zycewsya.aspxist ja aber für einen VB-Entwickler hier wohl eher uninteressant.
ciao Frank- Als Antwort markiert Thorsten DörflerModerator Samstag, 31. Juli 2010 15:46
-
Hallo Nico,
warum es mit VBFixedArray bzw. MarshalAs nicht klappt, hat Dir Thorsten bereits erläutert.
Und da Du nach Deinen anderen Beiträgen die Übertragung über den SerialPort erfolgt,
haben die Attribute keine Bedeutung.Um das Intialisieren des Puffers nicht zu vergessen, bleiben Dir zwei Möglichkeiten:
Entweder Du verwendest spezielle Konstrukturen - eher häßlich wenn es mehr als eine
Handvoll Meldungen sind, zumal immer alle Felder gesetzt werden müssen - siehe StrukturenOder Methoden für die einzelnen Meldungen, wo man via Hilfsmethoden das gängigste
vereinfachen kann - an Deinen Deinen Code angelehnt könnte das z. B. aussehen:Public Sub InitializeData() Data = New Byte(7) {} End Sub Public Sub InitializeData(ByVal ParamArray bytes() As Byte) Data = New Byte(7) {} If bytes IsNot Nothing AndAlso bytes.Length > 0 Then If bytes.Length > 8 Then Throw New ArgumentException("Maximal 8 Bytes in einer Nachricht zugelassen") End If For index As Integer = 0 To bytes.Length - 1 Data(index) = bytes(index) Next End If End Sub Public Shared Sub SendTestMessage() Dim testmsg As New CANRawMsg ' ... weitere Parameter ausgelassen testmsg.InitializeData() ' oder testmsg.InitializeData(0, 1) End Sub
Letztere weist die Bytes entsprechend zu und reduziert das obige
auf eine Anweisung. Wobei Du auch schreiben kannst:ReDim .Data(7)<br/> .Data(0) = 0<br/> .Data(1) = 1<br/>
testmsg.InitializeData(0, 1, 2, 3, 4, 5, 6, 7)<br/>
Zu empfehlenen ist Data als Private zu erklären, damit man keine Stellen vergisst,
und ausschliesslich über die Methoden zugreift (bei Mogeln gibts sonst schnell wieder Probleme).Eine Alternative wäre anstatt einer Structure eine Class zu verwenden.
Damit hast Du ein wenig mehr Overhead - siehe obige Einführung.
Dann darfst aber auch etwas schreiben wie:Private Data As Byte() = New Byte(7) {}
Wobei ich den Weg über die InitializeData Methode (den Namen darfst Du gerne ändern)
gehen würde. Denn versendest Du viele Meldungen ist eine Anlage auf dem Stack schon
ressourcenschonender. Und erfordert einfach ein klein wenig mehr an Disziplin.Redim bringt an der Stelle übrigens auch Overhead, da es in einen (überflüssigen) Methodenaufruf
umgesetzt wird, der hier letztendlich durch ein New Byte(7) {} effizienter realisiert werden kann.Gruß Elmar
- Als Antwort markiert Thorsten DörflerModerator Samstag, 31. Juli 2010 15:46
Alle Antworten
-
Hallo Nico,
Problematisch ist die Zeile mit <Marshal... Zuvor habe ich <VBFixedArray> verwendet.
.NET unterstützt keine Arrays mit festen Längen. VBFixedArray bzw. MarshalAs sind nur in InterOp Szenarien von Bedeutung. Hier übernimmt die Runtime dann die entsprechende Dimensionierung und Übergabe. Somit bleibt nur die Möglichkeit das Array zuvor über die ReDim Anweisung zu dimensionieren.
Thorsten Dörfler
Microsoft MVP Visual Basic
vb-faq.de- Als Antwort markiert Thorsten DörflerModerator Samstag, 31. Juli 2010 15:46
-
Hallo Nico,
Auch für VBFixedArray gilt schon:[VBFixedArrayAttribute-Klasse (Microsoft.VisualBasic)]
http://msdn.microsoft.com/de-de/library/microsoft.visualbasic.vbfixedarrayattribute.aspxVBFixedArrayAttribute dient lediglich der Information und reserviert keinen Speicher. Es verändert die Verwendung von Arrays in Strukturen und nicht lokalen Variablen durch Methoden oder API-Aufrufe, die VBFixedArrayAttribute erkennen. Beachten Sie, dass dieses Attribut kein Array mit variabler Länge in ein Array fester Länge umwandelt, und dass Sie mithilfe der Dim-Anweisung oder der ReDim-Anweisung Arrayspeicher zuordnen müssen.
_____________________Nur beiläufig erwähnt ... es gäbe unter .NET zum Beispiel: [Puffer fester Größe (C#-Programmierhandbuch)]
http://msdn.microsoft.com/de-de/library/zycewsya.aspxist ja aber für einen VB-Entwickler hier wohl eher uninteressant.
ciao Frank- Als Antwort markiert Thorsten DörflerModerator Samstag, 31. Juli 2010 15:46
-
Hallo Nico,
warum es mit VBFixedArray bzw. MarshalAs nicht klappt, hat Dir Thorsten bereits erläutert.
Und da Du nach Deinen anderen Beiträgen die Übertragung über den SerialPort erfolgt,
haben die Attribute keine Bedeutung.Um das Intialisieren des Puffers nicht zu vergessen, bleiben Dir zwei Möglichkeiten:
Entweder Du verwendest spezielle Konstrukturen - eher häßlich wenn es mehr als eine
Handvoll Meldungen sind, zumal immer alle Felder gesetzt werden müssen - siehe StrukturenOder Methoden für die einzelnen Meldungen, wo man via Hilfsmethoden das gängigste
vereinfachen kann - an Deinen Deinen Code angelehnt könnte das z. B. aussehen:Public Sub InitializeData() Data = New Byte(7) {} End Sub Public Sub InitializeData(ByVal ParamArray bytes() As Byte) Data = New Byte(7) {} If bytes IsNot Nothing AndAlso bytes.Length > 0 Then If bytes.Length > 8 Then Throw New ArgumentException("Maximal 8 Bytes in einer Nachricht zugelassen") End If For index As Integer = 0 To bytes.Length - 1 Data(index) = bytes(index) Next End If End Sub Public Shared Sub SendTestMessage() Dim testmsg As New CANRawMsg ' ... weitere Parameter ausgelassen testmsg.InitializeData() ' oder testmsg.InitializeData(0, 1) End Sub
Letztere weist die Bytes entsprechend zu und reduziert das obige
auf eine Anweisung. Wobei Du auch schreiben kannst:ReDim .Data(7)<br/> .Data(0) = 0<br/> .Data(1) = 1<br/>
testmsg.InitializeData(0, 1, 2, 3, 4, 5, 6, 7)<br/>
Zu empfehlenen ist Data als Private zu erklären, damit man keine Stellen vergisst,
und ausschliesslich über die Methoden zugreift (bei Mogeln gibts sonst schnell wieder Probleme).Eine Alternative wäre anstatt einer Structure eine Class zu verwenden.
Damit hast Du ein wenig mehr Overhead - siehe obige Einführung.
Dann darfst aber auch etwas schreiben wie:Private Data As Byte() = New Byte(7) {}
Wobei ich den Weg über die InitializeData Methode (den Namen darfst Du gerne ändern)
gehen würde. Denn versendest Du viele Meldungen ist eine Anlage auf dem Stack schon
ressourcenschonender. Und erfordert einfach ein klein wenig mehr an Disziplin.Redim bringt an der Stelle übrigens auch Overhead, da es in einen (überflüssigen) Methodenaufruf
umgesetzt wird, der hier letztendlich durch ein New Byte(7) {} effizienter realisiert werden kann.Gruß Elmar
- Als Antwort markiert Thorsten DörflerModerator Samstag, 31. Juli 2010 15:46
-
Hallo Nico,
nicht "redimenisionieren" sondern gleich dimensionieren ;-)
Eine Array Variable hat anfangs keinen Wert (Nothing) und das bereits gezeigte
erzeugt das ersten (und bei Dir wohl auch letzte) Array.Private Data As Byte() = New Byte(7) {}
Redim ist nur dort von Wert, wo vorher bereits ein Array zugewiesen war/erzeugt wurde
und dieses in der Größe verändert (und der Inhalt erhalten bleiben soll).
In allen anderen Fällen erzeugt es unnötigen Overhead.Gruß Elmar