Toon posts:

[c#] Generic oplossing voor Equals van 2 onbekende objecten

Pagina: 1
Acties:

Onderwerpen


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 02-08-2021
Beetje wazige topictitel misschien, maar ik leg het even uit.

Ik heb een situatie waarin ik classes genereer.
Al de gegenereerde classes erven over van een (eigen) baseclass.

nu wil ik een Equals() functie schrijven waarin ik kan zien of object1 gelijk is aan object2.
Echter is het type van object1 en object2 onbekend.

Dat wil zeggen. Ze zijn gegenereerd, erven over van de baseclass, maar ik wil ze vergelijken op specifieke gegevens.

resumé:
Class1 heeft property 'naam'
Class2 heeft property 'kleur'
Class3 heeft property 'x'
...
etc.

Ze erven allen over van baseclass.

Nu heb ik 2 van die objecten (wel allebij van dezelfde class, maar ik weet niet welke) en wil ik kijken of deze objecten gelijk zijn.

Mijn Class1 heeft de onderstaande functie:
C#:
1
2
3
4
public bool Equals(Class1 obj)
{
  return naam.Equals(obj.naam);
}


Echter kan ik deze niet aanroepen, omdat in mijn programma ik niet weet dat het een Class1 betreft.

Nu heb ik het volgende, wat wel werkt:
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
40
41
42
43
44
45
46
47
48
49
50
51
public class BaseClass
{
    public override bool Equals(object obj)
    {
        if (obj == null || GetType() != obj.GetType())
            return false;

        if (obj is Class1)
        {
            Class1 c1 = (Class1)this;
            Class1 c2 = (Class1)obj;

            return c1.Equals(c2);
        }
        else if (obj is Class2)
        {
            //...etc.
        }
        return false;
    }
}

public class Class1 : BaseClass
{
    public string naam;

    public bool Equals(Class1 obj)
    {
        return naam.Equals(obj.naam);
    }
}

class Program
{
    static void Main(string[] args)
    {
        //dus puur om te testen even wat objecten aanmaken
        Class1 c1_0 = new Class1();
        c1_0.naam = "bas";
        Class1 c1_1 = new Class1();
        c1_1.naam= "bas";


        //hier doen we dus alsof we niet meer weten wat het is.
        BaseClass b1 = c1_0;
        BaseClass b2 = c1_1;

        //en hier vergelijken we ze, wat dus goed gaat
        Console.WriteLine(b1.Equals(b2));
    }
}


Echter is wel duidelijk dat je zoiets met generics wilt oplossen.
Ik wil dus niet voor al mijn classes zeggen:
C#:
1
2
3
if (obj is Class1) { ... }
if (obj is Class2) { ... }
if (obj is Class3) { ... }



voordat mensen nu gaan roepen "je ontwerp is fout" etc., zal ik even iets meer uitleg geven:

Het gaat om class generatie adhv een database.
Ik wil de objecten cachen, en genereer daarom nu in alle classes een eigen caching mechanisme. Dit werkt prima, maar 99% van de code van het mechanisme komt in AL die classes terug.
Hierdoor vind ik mijn dll te groot worden, en ik wil dit op een ander niveau regelen. Zodoende wil ik op het niveau van de baseclass mijn caching code plaatsen, echter is die één procent code die wel class specifiek is nogal lastig te bouwen als ik niet weet welke class het is.
Ik weet namelijk niet of ik op naam moet vergelijken of op kleur of lengte of whatever..

Hoe vlieg je zoiets aan?

This message was sent on 100% recyclable electrons.


  • Wijnbo
  • Registratie: December 2002
  • Laatst online: 01-06 08:16

Wijnbo

Electronica werkt op rook.

Hele stomme vraag misschien, maar kun je die 99% zelfde code niet in de baseclass kiepen? En verder, je kunt toch gewoon kijken of je object van het zelfde type is? Op moment dat ze van het zelfde type zijn, ga je gewoon met reflection er door heen en kijk je naar alle property waarden etc...

In de baseclass:

Pseudo:

code:
1
2
3
4
5
6
7
8
9
10
11
12
boolean equals(object a)
{
  if not object a zelfde type als object b
  {
    return false
  }
  else
  {
    foreach alle properties van object a en vergelijk met property van b. ongelijk? exit for, return false.
    return true
  }
}

[Voor 87% gewijzigd door Wijnbo op 07-07-2011 13:04]


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 02-08-2021
Wijnbo schreef op donderdag 07 juli 2011 @ 13:00:
Hele stomme vraag misschien, maar kun je die 99% zelfde code niet in de baseclass kiepen?
euh ja daarvoor open ik dit topic.
Punt is dat ik niet weet hoe ik dan die 1% moet gaan doen
Je kunt toch gewoon kijken of je object van het zelfde type is? Op moment dat ze van het zelfde type zijn, ga je gewoon met reflection er door heen en kijk je naar alle property waarden etc...
Ja en nee.
Zoals ik al zei is het een caching voor objecten die uit DB komen.
Wat ik nu heb zijn 2 objecten. 1 oud, (uit cache) en 1 nieuw (uit DB)
Om te zorgen dat ik niet 2 versies van 1 object ga gebruiken in mijn applicatie wil ik deze vergelijken en als ze hetzelfde zijn de referenties naar object1 naar object2 laten wijzen of andersom.

Echter kan het zijn dat het nieuwe object anders is dan het oude, omdat het record in de DB in die tussentijd is gewijzigd.
De PK's van de objecten zijn echter wel hetzelfde, en daarop moet dus gecontroleerd worden. niet zomaar op 'alle property waarden'.

[Voor 57% gewijzigd door BasieP op 07-07-2011 13:05]

This message was sent on 100% recyclable electrons.


  • BCC
  • Registratie: Juli 2000
  • Laatst online: 22:04
Ja, of implementeer in alle klasses naast deze equals functie een functie die expliciet een equals string oplevert. De implementatie kan je dan per klasse anders maken en defaulten in je base class.

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 class BaseClass 
{ 
    public override bool Equals(object obj) 
    { 
       return EqualsString.Equals(obj.EqualsString); 
    }

    public string EqualsString() 
    { 
        return ""; 
    } 
} 

public class Class1 : BaseClass 
{ 
    public string naam; 

    public override string EqualsString() 
    { 
        return naam; 
    } 
} 
}


Vraag is of je Equals wel wil overriden. Misschien kun je beter een LooksLike functie implementeren oid. Hangt af van de rest van de rest van je app.

En wat je dan aan het doen bent is ducktyping (handig voor google) Wikipedia: Duck typing

[Voor 73% gewijzigd door BCC op 07-07-2011 13:09]


  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

ASSUME makes an ASS out of U and ME


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 02-08-2021
BCC schreef op donderdag 07 juli 2011 @ 13:02:
Ja, of implementeer in alle klasses naast deze equals functie een functie die expliciet een equals string oplevert. De implementatie kan je dan per klasse anders maken en defaulten in je base class.

code:
1
2
3
4
5
6
7
8
9
public bool Equals(Class1 obj) 
{ 
  return EqualsString.Equals(obj.EqualsString()); 
}

public string EqualsString()
{
  return name;
}
mja dat had ik niet helemaal duidelijk gezegt, maar soms zijn het meerdere objecten, die niet altijd string zijn.
Je hebt gewoon per gegenereerde class een PK.
Soms is dat een decimal, soms een integer, soms 2 integers, soms een int en een string.
Die wil je vergelijken.
Jij mag me SP nog een keer lezen. ik weet hoe je een normale Equals() implementeert. Dit is echter geen normale.


Waar ik zelf aan zit te denken is om de baseclass een list<object> Keys; te geven, en elke class deze te laten vullen met zijn eigen 'keys'.
De .Equals in de baseclass kan dan zoiets doen:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
public override Equals(object obj)
{
    if (obj == null || GetType() != obj.GetType())
        return false;

    for (int i = 0; i< Keys.Count(); i++)
    {
        if (!Keys[i].Equals(obj.Keys[i]))
            return false;
    }
    return true;
}

This message was sent on 100% recyclable electrons.


  • steffex
  • Registratie: Augustus 2003
  • Laatst online: 18-05 18:24

steffex

Dev nerd

BasieP schreef op donderdag 07 juli 2011 @ 13:21:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
public override Equals(object obj)
{
    if (obj == null || GetType() != obj.GetType())
        return false;

    for (int i = 0; i< Keys.Count(); i++)
    {
        if (!Keys[i].Equals(obj.Keys[i]))
            return false;
    }
    return true;
}
krijg je met die for loop geen problemen als je Keys niet in dezelfde volgorde staan?

[Voor 39% gewijzigd door steffex op 07-07-2011 13:28]

Freelance developer - Gadget freak - Motorrijder


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 02-08-2021
steffex schreef op donderdag 07 juli 2011 @ 13:28:
[...]


krijg je met die for loop geen problemen als je Keys niet in dezelfde volgorde staan?
ja, daarom moet de volgorde hetzelfde zijn, of ik moet er KeyValuePairs van maken..

This message was sent on 100% recyclable electrons.


  • Roxors
  • Registratie: April 2009
  • Laatst online: 31-05 12:45
Om te zorgen dat ik niet 2 versies van 1 object ga gebruiken in mijn applicatie wil ik deze vergelijken en als ze hetzelfde zijn de referenties naar object1 naar object2 laten wijzen of andersom.
Kan je niet tijdens het aanmaken van een object in de constructor van dat object een GUID (ObjectId ofzo) aanmaken, zodat je deze later kunt vergelijken?
Echter kan het zijn dat het nieuwe object anders is dan het oude, omdat het record in de DB in die tussentijd is gewijzigd.
De PK's van de objecten zijn echter wel hetzelfde, en daarop moet dus gecontroleerd worden. niet zomaar op 'alle property waarden'.
Misschien is het handig om een hash van het object bij te houden en te vergelijken. Of on the fly berekenen en vergelijken.

Edit: Overigens neem ik aan dat je met caching bedoelt het cachen van de properties van een object, en niet het cachen van het hele object zelf? Anders had ik niet verwacht dat je je cache mechanisme in de classes zelf stopt.

[Voor 12% gewijzigd door Roxors op 07-07-2011 13:46]


  • JaWi
  • Registratie: Maart 2003
  • Laatst online: 10-04 18:12

JaWi

maak het maar stuk hoor...

Als ik dit zo lees, dan zou ik in de Equals van je BaseClass alleen kijken of de te-vergelijken-object niet null is en van hetzelfde type, en dan deze Equals weer overriden in je specifieke subklasse, waar je eerst kijkt of de Equals van je superklasse "true" teruggeeft, en zo ja, dan kun je veilig casten naar je concrete subtype en de specifieke vergelijking doen.

Pseudo code:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class BaseClass
{
    public override bool Equals(object obj)
    {
        if (obj == null || GetType() != obj.GetType())
            return false;
        return true;
    }
}
...
public class Class1 : BaseClass
{
    public string naam;

    public override bool Equals(object obj)
    {
        if (!base.Equals(obj))
           return false;

        return naam.Equals(((Class1)obj).naam);
    }
}


Of begrijp ik je TS (nog steeds) niet?

Statistics are like bikinis. What they reveal is suggestive, but what they hide is vital.


  • Danot
  • Registratie: Juni 2003
  • Niet online
Er zal vast een goede reden zijn, maar ik ben benieuwd. Waarom gebruik je geen NHibernate of Entity Framework?

  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 02-08-2021
JaWi schreef op donderdag 07 juli 2011 @ 13:51:
Als ik dit zo lees, dan zou ik in de Equals van je BaseClass alleen kijken of de te-vergelijken-object niet null is en van hetzelfde type, en dan deze Equals weer overriden in je specifieke subklasse, waar je eerst kijkt of de Equals van je superklasse "true" teruggeeft, en zo ja, dan kun je veilig casten naar je concrete subtype en de specifieke vergelijking doen.

Pseudo code:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class BaseClass
{
    public override bool Equals(object obj)
    {
        if (obj == null || GetType() != obj.GetType())
            return false;
        return true;
    }
}
...
public class Class1 : BaseClass
{
    public string naam;

    public override bool Equals(object obj)
    {
        if (!base.Equals(obj))
           return false;

        return naam.Equals(((Class1)obj).naam);
    }
}


Of begrijp ik je TS (nog steeds) niet?
Nee ik denk dat jij me heel goed begrijpt.

Dit is inderdaad de oplossing.
Ik had op de een of andere manier in mijn hoofd dat je vanaf je programma eerst naar de baseclass moest, en dan pas naar je subclass, en dat kan niet omdat je niet weet welke dat is.

Dmv overerving van de Equals in zowel je baseclass als je subclass ga je natuurlijk eerst naar je subclass, waarin je dan wel weer je baseclass kunt aanroepen. :)

many thanks.

This message was sent on 100% recyclable electrons.


  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 01-06 16:53

RayNbow

Kirika <3

Je kunt het ook omdraaien. In plaats van dat de subclasses altijd de superclass methode aanroepen, kun je ook ervoor zorgen dat de superclass de subclass methode aanroept:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class Base
{
    public sealed override bool Equals(object obj)
    {
        return obj != null && GetType() == obj.GetType() && DoEquals(obj);
    }
        
    public abstract bool DoEquals(object obj);
}

public class Sub : Base
{
    public override bool DoEquals(object obj)
    {
        /* ... */
    }
}

Ipsa Scientia Potestas Est
NNID: ShinNoNoir

Pagina: 1


Tweakers maakt gebruik van cookies

Tweakers plaatst functionele en analytische cookies voor het functioneren van de website en het verbeteren van de website-ervaring. Deze cookies zijn noodzakelijk. Om op Tweakers relevantere advertenties te tonen en om ingesloten content van derden te tonen (bijvoorbeeld video's), vragen we je toestemming. Via ingesloten content kunnen derde partijen diensten leveren en verbeteren, bezoekersstatistieken bijhouden, gepersonaliseerde content tonen, gerichte advertenties tonen en gebruikersprofielen opbouwen. Hiervoor worden apparaatgegevens, IP-adres, geolocatie en surfgedrag vastgelegd.

Meer informatie vind je in ons cookiebeleid.

Sluiten

Toestemming beheren

Hieronder kun je per doeleinde of partij toestemming geven of intrekken. Meer informatie vind je in ons cookiebeleid.

Functioneel en analytisch

Deze cookies zijn noodzakelijk voor het functioneren van de website en het verbeteren van de website-ervaring. Klik op het informatie-icoon voor meer informatie. Meer details

janee

    Relevantere advertenties

    Dit beperkt het aantal keer dat dezelfde advertentie getoond wordt (frequency capping) en maakt het mogelijk om binnen Tweakers contextuele advertenties te tonen op basis van pagina's die je hebt bezocht. Meer details

    Tweakers genereert een willekeurige unieke code als identifier. Deze data wordt niet gedeeld met adverteerders of andere derde partijen en je kunt niet buiten Tweakers gevolgd worden. Indien je bent ingelogd, wordt deze identifier gekoppeld aan je account. Indien je niet bent ingelogd, wordt deze identifier gekoppeld aan je sessie die maximaal 4 maanden actief blijft. Je kunt deze toestemming te allen tijde intrekken.

    Ingesloten content van derden

    Deze cookies kunnen door derde partijen geplaatst worden via ingesloten content. Klik op het informatie-icoon voor meer informatie over de verwerkingsdoeleinden. Meer details

    janee