comment gerer des paramètres de type variable dans une fonction ou une procédure
bonjour,
j'essaye d'écrire une classe qui permet de lire un fichier "à la manière" du pascal, c'est à dire permettant de lire directement des variables typées.
voici le code de ma classe :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| Public Class TFileType
Private TypeSize As Integer
Private fs As FileStream
Public Sub New(ByVal tSize As Integer, ByVal FileName As String)
TypeSize = tSize
fs = New FileStream(FileName, FileMode.Open, FileAccess.ReadWrite)
End Sub
Public Sub free()
fs.Close()
End Sub
Public Function eof() As Boolean
Return (fs.Position = fs.Length)
End Function
Function read(ByRef Buffer As Object) As Integer
Return fs.Read(buffer, 0, TypeSize)
End Function
Public Sub write(ByRef Buffer As Object)
fs.Write(Buffer, 0, TypeSize)
End Sub
End Class |
j'utilise la classe de cette façon :
je voudrais lire un fichier article
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Public Structure TArticle
Dim codbar1 As Integer
Dim codbar2 As Integer
Dim LongueurChaine As Byte
<VBFixedString(30)> Dim nom As String
Dim famille As Byte
Dim remise As Byte
Dim prix As Integer
Dim actif As Byte
End Structure
Const CheminFichierArticle As String = "E:\ARTICLE"
Dim fa As New TFileType(46, CheminFichierArticle)
Dim article as TArticle
fa.read(article)
fa.free() |
un problème ce pose avec le méthode read ( et write ) de ma classe :
Code:
1 2 3
| Function read(ByRef Buffer As Object) As Integer
Return fs.Read(buffer, 0, TypeSize)
End Function |
la méthode read devant lire des types différents, j'utilise un buffer de type Object , mais le compilateur refuse en me disant qu'il ne peut pas transtyper un TArticle en Object
ma question :
comment faire pour passer à la méthode read une variable par référence dont le type n'est pas connu à l'avance. (par référence car la méthode read doit modifier cette variable )
merci d'avance.
une solution possible mais pas top
une solution possible mais pas très élégante à mon gout car la classe doit gérer d'avance tous les types possibles :
Code:
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
|
Imports System.IO
Public Class TFileType(Of type)
Private TypeSize As Integer
Private fs As FileStream
Private BinReader As BinaryReader
Private BinWriter As BinaryWriter
Private v As type
Public Property article()
Get
Dim art As TArticle
With art
.codbar1 = BinReader.ReadInt32
.codbar2 = BinReader.ReadInt32
.LongueurChaine = BinReader.ReadByte
.nom = BinReader.ReadChars(30)
.nom = ModifieAccentChaine(.nom.Substring(0, .LongueurChaine))
.famille = BinReader.ReadByte
.remise = BinReader.ReadByte
.prix = BinReader.ReadInt32
.actif = BinReader.ReadByte
End With
Return art
End Get
Set(ByVal value)
Dim TabChar(29) As Char
With value
BinWriter.Write(.codbar1)
BinWriter.Write(.codbar2)
BinWriter.Write(.LongueurChaine)
TabChar = .nom
BinWriter.Write(TabChar)
BinWriter.Write(.famille)
BinWriter.Write(.remise)
BinWriter.Write(.prix)
BinWriter.Write(.actif)
End With
End Set
End Property
Public Sub New(ByVal FileName As String)
TypeSize = Len(v)
fs = New FileStream(FileName, FileMode.Open, FileAccess.ReadWrite)
BinReader = New BinaryReader(fs)
BinWriter = New BinaryWriter(fs)
End Sub
Public Sub free()
BinReader.Close()
BinWriter.Close()
fs.Close()
End Sub
Public Sub seek(ByVal index As Integer)
fs.Position = index * TypeSize
End Sub
Public Function eof() As Boolean
Return (fs.Position = fs.Length)
End Function
Function FileSize() As Integer
Return fs.Length \ TypeSize
End Function
End Class |
utilisé de cette façon :
Code:
1 2 3 4
|
Dim fa As New TFileType(Of TArticle)(CheminFichierArticle)
dim article as TArticle=CType(fa.article, TArticle) |
si quelqu'un à une meilleur idée, je suis preneur
merci.
peut être la meilleur solution :
en lisant l'excellent cours de Philippe Lasserre sur le site j'ai vu que l'on pouvait surcharger les méthodes Ctype d'une structure. C'est ce que j'ai fait : ( ajout de Byte() -> TArticle et TArticle -> Byte() )
Code:
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
|
Public Structure TArticle
Dim codbar1 As Integer
Dim codbar2 As Integer
Dim LongueurChaine As Byte
<VBFixedString(30)> Dim nom As String
Dim famille As Byte
Dim remise As Byte
Dim prix As Integer
Dim actif As Byte 'en principe boolean mais prend 2 octets en VB
Public Shared Widening Operator CType(ByVal buffer As Byte()) As TArticle
Dim art As New TArticle
With art
.codbar1 = bufferToInteger(buffer(0), buffer(1), buffer(2), buffer(3))
.codbar2 = bufferToInteger(buffer(4), buffer(5), buffer(6), buffer(7))
.LongueurChaine = buffer(8)
.nom = bufferToCharTab(9, 30, buffer)
.famille = buffer(39)
.remise = buffer(40)
.prix = bufferToInteger(buffer(41), buffer(42), buffer(43), buffer(44))
.actif = buffer(45)
End With
Return art
End Operator
Public Shared Widening Operator CType(ByVal art As TArticle) As Byte()
Dim buffer(45) As Byte
With art
IntegerToBuffer(.codbar1, 0, buffer)
IntegerToBuffer(.codbar2, 4, buffer)
buffer(8) = .LongueurChaine
CharTabToBuffer(9, 30, .nom, buffer)
buffer(39) = .famille
buffer(40) = .remise
IntegerToBuffer(.prix, 41, buffer)
buffer(45) = .actif
End With
Return buffer
End Operator
End Structure |
j'ai utilisé les fonctions et procédures suivantes pour les conversions : (je pense qu'elles peuvent être améliorées)
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
Public Function bufferToInteger(ByVal b1 As Byte, ByVal b2 As Byte, ByVal b3 As Byte, ByVal b4 As Byte) As Integer
Dim res As Integer = b4
res = (res << 8) + b3
res = (res << 8) + b2
res = (res << 8) + b1
Return res
End Function
Public Sub IntegerToBuffer(ByVal i As Integer, ByVal deb As Byte, ByRef buffer() As Byte)
buffer(deb) = CByte(i Mod 256)
i = i >> 8
buffer(deb + 1) = CByte(i Mod 256)
i = i >> 8
buffer(deb + 2) = CByte(i Mod 256)
i = i >> 8
buffer(deb + 3) = CByte(i Mod 256)
End Sub
Public Sub CharTabToBuffer(ByVal deb As Byte, ByVal count As Byte, ByRef TabChar() As Char, ByRef buffer() As Byte)
For i As Integer = 0 To count - 1
buffer(deb + i) = CByte(Asc(TabChar(i)))
Next i
End Sub |
voici le code complet de la classe :
Code:
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
|
Imports System.IO
Public Class TFileType(Of type)
Private TypeSize As Integer
Private fs As FileStream
Private v As type
Public Sub New(ByVal FileName As String)
TypeSize = Len(v)
fs = New FileStream(FileName, FileMode.Open, FileAccess.ReadWrite)
End Sub
Public Sub free()
fs.Close()
End Sub
Public Sub seek(ByVal index As Integer)
fs.Position = index * TypeSize
End Sub
Public Function eof() As Boolean
Return (fs.Position = fs.Length)
End Function
Function FileSize() As Integer
Return fs.Length \ TypeSize
End Function
Function read() As Byte()
Dim buffer(TypeSize) As Byte
fs.Read(buffer, 0, TypeSize)
Return buffer
End Function
Sub write(ByVal buffer() As Byte)
fs.Write(buffer, 0, TypeSize)
End Sub
End Class |
instancié de cette façon :
Code:
1 2
|
Dim fa As New TFileType(Of TArticle)(CheminFichierArticle) |
pour la lecture d'une variable de type TArticle :
Code:
1 2 3
|
dim article as New TArticle
article = CType(fa.read, TArticle) |
pour l'écriture :
Code:
1 2
|
fa.write(CType(article, byte())) |
merci pour tout commentaire qui permettrait d'améliorer cette solution.