webForumDet fria alternativet

Loopa igenom egenskaperna i ett objekt?

.NET

12 svar · 495 visningar · startad av Lukaspojken

Medlem sedan maj 20011 312 inlägg
Frågan#1

Om jag tex har ett objekt som ser ut ungefär enligt följande:

Public Class Person
    Private m_FirstName As String
    Private m_LastName

    Public Property FirstName() As String
        Get
            Return m_FirstName
        End Get
        Set(ByVal value As String)
            m_FirstName = value
        End Set
    End Property

    Property LastName() As String
        Get
            Return m_LastName
        End Get
        Set(ByVal value As String)
            m_LastName = value
        End Set
    End Property
End Class

Public Class XXX
    Sub Main()
        Dim Person1 As New Person
        Person1.FirstName = "Nisse"
    End Sub
End Class

I main instanserar jag objektet och sätter bara förnamnet men inte efternamnet. Så nu till min fråga: Finns det något bra sätt att loopa igenom objektets egenskaper för att se om dessa är satta eller inte?

Medlem sedan feb. 20002 300 inlägg
#2

Lukaspojken skrev:

I main instanserar jag objektet och sätter bara förnamnet men inte efternamnet. Så nu till min fråga: Finns det något bra sätt att loopa igenom objektets egenskaper för att se om dessa är satta eller inte?

Gör en metod Validate() i klassen Person som returnerar en boolean hurvida alla properties du har är korrekt ifyllda.

Medlem sedan maj 20011 312 inlägg
#3

Jag var nog lite otydlig i min frågeställning för det är inte det jag är ute efter utan det jag vill göra är att på ett smart sätt hämta upp alla egenskaper som är satta för ett objekt. Det man kan använda sig av är reflection. Något i stil med detta kan man använda sig av. Debug.writeline får givetvis ersättas med något annat men något i stil med detta borde lösa problemet...

        Dim typType As Type = Person.GetType
        Dim arrControls() As Reflection.FieldInfo
        Dim c As Integer

        arrControls = typType.GetFields(Reflection.BindingFlags.Public Or BindingFlags.GetField Or BindingFlags.Instance)

        For c = LBound(arrControls) To UBound(arrControls)
            If Not arrControls(c) Is Nothing Then
                Debug.WriteLine(arrControls(c).Name)
            End If
        Next

Om det finns något smartare sätt att göra detta på så tipsa gärna!

Medlem sedan maj 20012 812 inlägg
#4

Det beror på vad du menar med smartast?

Reflektions är smartast ut återanvändingssynpunkt, eftersom det kommer att fungerar på dina flesta objekt.

Men ur ett prestandasynpunkt så är det smartare att låta dina klasser inplementerar ett interface som gör samma sak för sin klass, då slipper du reflektion och tjänar några klockcyklar. Det kräver dock betydligt mer arbete för dig eftersom alla dina klasser måste implementerar detta interface för att du skall få det att fungerar som du vill.

- M

Medlem sedan maj 20011 312 inlägg
#5

Jag har också hört att reflektion inte är så bra ur prestandasynpunkt så man kanske inte alltid ska använda detta.

Kan du ge ett exempel på hur ditt lösningsalternativ skulle kunna se ut på ovanstående exempel? Det känns som att ett interface kan väl inte bara lösa det.

Medlem sedan feb. 20002 300 inlägg
#6

Lukaspojken skrev:

Jag har också hört att reflektion inte är så bra ur prestandasynpunkt så man kanske inte alltid ska använda detta.

Kan du ge ett exempel på hur ditt lösningsalternativ skulle kunna se ut på ovanstående exempel? Det känns som att ett interface kan väl inte bara lösa det.

En kombination av vad Gladh och jag skrev. Skapa ett interface IValidatable med en metod Validate(). Låt alla klasser som ska kunna valideras implementera interfacet.

Sen kan du iterera och validera alla objekt som implementerar ovanstående interface.

Medlem sedan maj 20011 312 inlägg
#7

Men vad är det som finns i metoden Validate? Skulle du kunna ge ett exempel på hur denna skulle kunna se ut i Person-klassen.

Medlem sedan feb. 20002 300 inlägg
#8

Lukaspojken skrev:

Men vad är det som finns i metoden Validate? Skulle du kunna ge ett exempel på hur denna skulle kunna se ut i Person-klassen.

public class Person : IValidatable
{
     private string forename;
     private string surname;

     [Properties...]

     public bool Validate()
     {
           if(forename == null || forename == String.Empty)
                return false;
           if(surname == null || surname == String.Empty)
                return false;
     }
}

Ungefär så. Det fina är att du kan validera alla typer av objekt som implementerar interfacet. Stoppa dem i en List<IValidatable>, iterera den och validera dem.

Undvik reflection i den mån det går.

Medlem sedan maj 20012 812 inlägg
#9

lukaspojken skrev:

Det känns som att ett interface kan väl inte bara lösa det.

Nja... Interface i sig kan inte lösa det till dig. Ett interface är som ett kontrakt. Alltså en specifikation på saker som din klass "lovar" att du kan kalla på, du kan dock aldrig vara säker på att saker och ting verkligen fungerar som interface säger, eftersom det är klassen i sig som bestämmer vad interfacet skall göra!!! Komplicerat?

Här kommer ett lite exempel:

Säg att jag har ett Interface som jag kallar IFordon, där jag säger att det finns 2 saker som ett IFordon kan göra.
1. Kör
2. Stanna.

Då kan mitt interface se ut så här:

public interface IFordon{
   void Kör();
   void Stanna();
}

Här är nu ett kontrakt som säger att alla klasser som implementerar mitt interface måste ha dessa 2 funktioner, vad som verkligen händer i dessa funktioner kan inte mitt interface styra.

Så här kommer 2 helt "korrekta" implementeringar av interfacet IFordon.

public class Bil : IFordon{

 public void Kör(){
    //-- implementerar kod för att köra bilen framåt.
 }

 public void Stanna(){
   //-- implementerar kod för att stanna bilen om den kör.
 }
}

public class Lastbil() : IFordon {

  public void Kör(){
    //-- implementerar kod för att tuta
  }
  
  public void Stanna(){
   //-- implementerar kod för att koppla loss släpvagnen
  }
}

ovanståend kod är helt legitimt och kompilatorn kommer inte ge dig ett fel, men om du säger till klassen att implementera IFordon så måste du implementerar dessa 2 metoder annars så får du fel, så du kan vara säker på att alla klasser som har interfacet IFordon verkligen har dessa 2 metoder, men du kan inte vara säker på vad de gör.

Och här ligger styrkan och svagheten med interfacet, du kan alltså göra olika saker i dessa 2 metoder beroende på vilken klass du är i.

Så i ditt exempel så får metoden Validate() i person inte samma kod som för klassen order, eftersom de inte har samma properties, men båda metoderna gör det du vill att de skall göra, validerar objektet.

- M

Medlem sedan maj 20012 812 inlägg
#10

phorper skrev:

Undvik reflection i den mån det går.

Både ja och nej, man kan lösa saker utan reflektion, men som visats i ovanstående exempel så blir det kanske mer kod att skriva och underhålla. Vilket i sig kan genererar fler felställen.

I detta exempel, så måste man ju komma ihåg att lägga till en check för propertisen i metoden validat om man lägger till en ny properties, med reflektion så löses detta automatisk eftersom den kolla runtime vilka properties som ditt objekt har.

Det hela handlar alltid om en avvägning, vad är viktigast. I detta specifika fall, så hade jag valt reflektion framför Interface metoden. Utvecklingshastighet och felmarginalerna är viktigare för mig än den sista prestandan... men det kan ändra sig beroende på kraven från kund.

Det är ju inte så att det tar sekunder för reflektions att kontrollera ett objekt, utan vi talar om millisekunder om ens det...

- M

Medlem sedan maj 20011 312 inlägg
#11

-> Gladh
Tack för beskrivningen av interface men den biten kan jag :) Det jag inte förstod var just det här med hur validate metoden skulle se ut och hur man skulle loopa igenom det. Jag tror jag förstår hur ni menar nu.

Men reflektion kanske ändå är något att föredra just för att snabba upp utvecklingshastigheten och minska felmarginalerna så som du säger.

Medlem sedan sep. 20011 914 inlägg
#12

Varför inte bara skapa en constructor och köra validering där. Så att du vet att allt fylls.

Public Class Person
    Public Sub New(ByVal firstname As String, ByVal lastname As String)
        MyBase.New
        If String.IsNullOrEmpty(firstname) Then
            Throw New ArgumentNullException(firstname)
        End If
        If String.IsNullOrEmpty(lastname) Then
            Throw New ArgumentNullException(lastname)
        End If
        Me.m_FirstName = firstname
        Me.m_LastName = lastname
    End Sub
    
    Private m_FirstName As String
    Private m_LastName As String
    Public Property FirstName As String
        Get
            Return m_FirstName
        End Get
        Set
            m_FirstName = value
        End Set
    End Property
    
    Private Property LastName As String
        Get
            Return m_LastName
        End Get
        Set
            m_LastName = value
        End Set
    End Property
End Class
Public Class XXX
    Private Sub Main()
        Dim Person1 As Person = New Person("Nisse", "")
    End Sub
End Class
Medlem sedan dec. 19996 721 inlägg
#13

1. Validering i konstruktorn är till för helt andra problem. Det finns inget som hindrar att det blir "fel" på objektet i efterhand, om valideringen sker där
2. Misstänker att det som önskas inte är validering genom exceptions

272 ms totalt · 4 externa anrop · v20260731065814-full.a51de22e
132 ms — deklarationer (db)
0 ms — hämta statistik (cache)
136 ms — hämta tråd, inlägg och bilagor (db)
125 ms — ändringar (db)