Sziasztok van egy olyan gondom, hogy egy feltetelt szeretnek ellenorizni a constructor-ban, ha az nem teljesul, akkor semmisitse meg. Az tiszta sor az objektum mar letrejott mikor a constructorban vagyok, de valami olyan megoldast keresek ami nem engedi az objektumhivatkozassal visszaterni. Onnettol kezdve pedig termeszetesen a GC lerendezi a dolgokat.
Van ra szamos workaround, (static method-boli hivas, factory pattern, stb) de olyat keresek amitol kifele transzparens lesz a belso ellenorzes.
Itt egy peldakod is:
public class ojjektum
{
public ojjektum(int kukuccs)
{
if (kukuccs == 0)
{
this = null; /// ez persze nem mukodik mert a "this" az readonly
}
}
}
Koszi elore is. :-)
PS: Java kategoriaba tettem mivel jelenleg nincsen C# kategoria es ehhez all a legkozelebb. Ha esetleg Javaban tud vki ugyanerre megoldast az is erdekelne. :-)
- 1643 megtekintés
Hozzászólások
stílusosan dobhatnál egy ArgumentOutOfRangeExceptiont (throw new ArgumentOutOfRangeExcetion("kukucs")) a konstruktorban
- A hozzászóláshoz be kell jelentkezni
Kosz, probaltam mar exception dobni vele (van is bent egyebkent is), elvileg null-al kellene visszaternie a hivo metodusba, de nem ez tortenik. Frankon eletben marad az objektum.
Ugyanaz a gaz ha "return null"-al probalkozom, vagy "this = null"-lal. Egyik sem engedelyezett constructorban (a this-re egyebkent se megy ertekadas).
Minél korszakalkotóbb ötlettel állsz elő, annál több hülyén kell átverekedned magadat.
- A hozzászóláshoz be kell jelentkezni
nem tudom milyen hívó metódusba kéne nullal visszatérnie, ez egy konstruktor, az egyeded null lesz (ez eléggé könnyen bizonyítható), a kivételt lekezeled
- A hozzászóláshoz be kell jelentkezni
"ez egy konstruktor, az egyeded null lesz (ez eléggé könnyen bizonyítható)"
Ez eddig is stimmelt. Meg lett a baj:
nUnit -tal teszteltem, ennel a pontnal alandoan elakadt es tevesen jelzett vissza, az alabbi koddal leprobaltam, igy mukodik rendesen nUnit nelkul:
public class ConditionalObject
{
public ConditionalObject(string name)
{
if (name.Equals(""))
{
throw new System.ArgumentOutOfRangeException(
this.ToString() + ": Unable to create new object without identifier.");
}
}
}
public class CallerClass
{
public static void Main()
{
ConditionalObject obj = new ConditionalObject("");
Console.WriteLine(( obj == null ) ? "null" : "not null");
}
}
Tanulsag, hatha mas is belefut: Az nUnit-tal valo ellenorzesnel megteveszto lehet a "piros" visszajelzes egy hasonlo szituaciora felteteles konstruktornal:
[Test]
public void TestASN1ObjectConstructorWithNoIdentifier()
{
Assert.IsNull(new MyASN1Codec(""));
}
Ha megadok egy stringet argumentumnak, akkor is "piros"-sal jon vissza, mivel akkor meg mar letezik az objektum, igy hamis lesz a feltetel. (Persze nUnittal is meg lehet csinalni, csak nem igy)
/* Megneztem a visszatereset a legfelso kodnak a WriteLine-ig nem jut el, (valszeg a catch hianya miatt) de mar nem latok, megyek aludni. Koszi megegyszer. */
Minél korszakalkotóbb ötlettel állsz elő, annál több hülyén kell átverekedned magadat.
- A hozzászóláshoz be kell jelentkezni
Nem lesz ez ennyire egyszeru, tegnap megsem oldodott meg. Ma egy arnyalatnyival kipihentebben ujbol elovettem a problemat, es ugyanaz... Nem az nUnit zavart be, hanem valoban nem mukodik.
Itt a tegnapi kod "elkapott" kivetellel:
using System;
public class ConditionalObject
{
public ConditionalObject(string name)
{
try
{
if (name.Equals(""))
{
throw new Exception(
this.ToString() + ": Unable to create new object without identifier.");
}
}
catch (Exception AException)
{
Console.WriteLine(AException.Message);
}
}
}
public class CallerClass
{
public static void Main()
{
ConditionalObject obj = new ConditionalObject("");
Console.WriteLine(obj == null ? "null" : "not null");
}
}
Nezzunk hozza egy igazsagtablazatot is:
Hivoertek Eredmeny Kivetel vegrehatjasa
"" "not null"!! igen
"T" "not null" nem
Kivetel elkapasa nelkul:
"" /* nem jut el idaig */ igen
(a rossz eredmenyt ket felkialtojellel jeloltem meg, ennek null-nak kellene lennie)
Minél korszakalkotóbb ötlettel állsz elő, annál több hülyén kell átverekedned magadat.
- A hozzászóláshoz be kell jelentkezni
ne nyeld le a konstruktorban a kivételt
public class ConditionalObject
{
public ConditionalObject(string name)
{
if (name == String.Empty)
{
throw new ArgumentException("name");
}
//todo
}
}
public class CallerClass
{
public static void Main()
{
ConditionalObject obj = null;
try
{
obj = new ConditionalObject(String.Empty);
}
catch
{
//hoppa
}
Console.WriteLine(obj == null ? "null" : "not null");
}
}
kimenet "" esetén: null, "T" esetén: not null
- A hozzászóláshoz be kell jelentkezni
Kivulrol eddig is le tudtam kezelni, ez nem volt gond. :-)
Ez egy abstract class amit kb. 100-120 masik osztaly fog orokolni ami egyenkent akar 15-20 masik hivoosztalybol lesz inditva, a hibauzenet es a kezeles modja mindegyiknel ugyanaz KELL, hogy legyen. Ezert nem latom ertelmet, hogy kulsoleg kezeltessem aztan minden leszarmaztatott osztalyban kezeljem ugyanazt mert plusz munkat csinalok vele.
Minél korszakalkotóbb ötlettel állsz elő, annál több hülyén kell átverekedned magadat.
- A hozzászóláshoz be kell jelentkezni
figyelj, nem lehetne ezt megoldani vmilyen "marker"-rel? Pl. egy MarkDisposable property-n keresztul, ami boolean-kent ha igazza valik akkor a gc prioritast kap a peldany kiirtasara.
A manualis irtasra korabban is gondoltam, de nem akarom IDisposable-a tenni az osszes leszarmazottat is (ertheto okokbol).
Minél korszakalkotóbb ötlettel állsz elő, annál több hülyén kell átverekedned magadat.
- A hozzászóláshoz be kell jelentkezni
Ne akarj ilyesmit!
Tervezd ugy a programodat, hogy ne kelljen olyan "new" neked ami null-t ad vissza.
- A hozzászóláshoz be kell jelentkezni
Ez a baj, hogy odaig sem jutok el, hogy a new null-t adjon vissza. (lasd: fenti pelda, igazsagtablazat)
(A kivetelek a call stackben gyulnek ossze tipus szerint szetvalogatva, nem pedig a constructor ter vissza null-lal).
Minél korszakalkotóbb ötlettel állsz elő, annál több hülyén kell átverekedned magadat.
- A hozzászóláshoz be kell jelentkezni
Ocsmany modon, de megoldottam static metodusboli hivassal:
using System;
public class ConditionalObject
{
private ConditionalObject()
{
}
public static ConditionalObject SafeInit(string AName)
{
ConditionalObject _obj = null;
try
{
_obj = new ConditionalObject();
if (AName.Equals(""))
{
throw new ArgumentException(_obj.ToString() +
": Unable to create new object without identifier.");
}
}
catch (ArgumentException AException)
{
Console.WriteLine(AException.Message);
return null;
}
return _obj;
}
}
public class CallerClass
{
public static void Main()
{
ConditionalObject obj = ConditionalObject.SafeInit("");
Console.WriteLine(obj == null ? "null" : "not null");
}
}
Egyelore megyek vele igy tovabb, de keresni fogok erre valamilyen normalis megoldast, mert ez igy gany.
Minél korszakalkotóbb ötlettel állsz elő, annál több hülyén kell átverekedned magadat.
- A hozzászóláshoz be kell jelentkezni
Miért ocsmány? Erre a problémára ez a jó megoldás, nem a konstruktor hekkelése, ami egyébként is elég ingoványos terület.
Viszont ha még a gyártófüggvényben elkapod a kivételt, akkor nem sok értelme van szerintem try-catch-et használni, főleg nincs mindenképpen létrehozni a példányt.
public static ConditionalObject CreateInstance (string name)
{
return (name == null || name.Length == 0) ? null : new ConditionalObject();
}
Oszt jónapot.
- A hozzászóláshoz be kell jelentkezni
"Miért ocsmány?"
Mert kifele nem lesz transzparens az ellenorzes. Egyseges API-t akartam midenutt, mert a kesobbiekben ahany objektum szarmazik majd le belole, annyifele parameterlistaja lehet az azonositas elokeszitesere, igy viszont a statikus metodust kell utantolteni ami egyeb okokbol majd problemas lesz.
Kell a try/catch kulonben kivul kellene megoldani, ill. peldanyt mindenkeppen letre kell hozni az ellenorzes idejere, mivel nem minden leszarmazottban fog csak bejovo parametereket ellenorizni, hanem azokat elobb elo kell keszitenie egy letezo peldannyal, majd a vegen a kiertekelesek alapjan pedig eldonti, hogy ez egy valid vagy invalid object lett.
Fentebb irtam, hogy az IDisposable sem jo, mert azt a kepesseget meg viszi magaval a leszarmazottakba is (nem szabadna) - ami tobb szaz/ezer is lehet.
Minél korszakalkotóbb ötlettel állsz elő, annál több hülyén kell átverekedned magadat.
- A hozzászóláshoz be kell jelentkezni
A konstruktor vagy kivételt dob, vagy visszadja az objektumot. Nem adhat vissza null-t. Ez a nyelv specifikációjban benne van.
Szerintem specifikáld pontosabban a problémát, hogy mit szeretnél megoldani. Szinte biztos, hogy létezik rá bejáratott, szép tervezési minta. A félszavaid alapján viszont lehetetlen megmondani, hogy melyik az.
- A hozzászóláshoz be kell jelentkezni
"A konstruktor vagy kivételt dob, vagy visszadja az objektumot. Nem adhat vissza null-t. Ez a nyelv specifikációjban benne van."
Igen, ezeket kinyomoztam kozben. Ket jarhato ut van, az egyik a static method elohivas, a masik pedig az IDisposable.
"Szerintem specifikáld pontosabban a problémát, hogy mit szeretnél megoldani.
Megprobalom a rovidebbik valtozatot, mert ha az egesz koncepciot vazolnam fel akkor jovo heten is itt ulnenk. :-) Ezert probaltam fent is tomorebben korbeirni.
Ezt a reszet az algoritmusnak legjobban egy elosztott alkalmazasszerverhez tudnam hasonlitani (nem egeszen az), amely dinamikusan (futas idoben) betoltott modulokat fog futtatni. Az eroforrasok adottak, egy-egy modul betoltodik, megkapja a kert eroforrasokat - ha van ra jogosultsaga - elvegzi a dolgat, majd tavozik, ill tarolja a resultot. Vannak olyan modulok, amelyek orakig is bent csucsulhetnek, dolgoznak, vagy eppen varnak mas modulok vegeztere, de vannak olyanok is amelyek masodpercenkent szazszor is betoltodhetnek (amelyeket nyilvan esszeru cachelni is). A fenti ellenorzes egyszer mindenkeppen le fog futni amikor betoltodik, ill. menet kozben tobbszor is lefuthat elore meghatarozhatatlan alkalommal, a modultol fuggoen. Minden modulban van legalabb egy osztaly amelyik ebbol az osztalybol van leszarmaztatva, mivel a modul az osztott eroforrasokat ezen keresztul eri el.
Tobb oka van amiert a constructor-hackinget probaltam preferalni a fentiekben:
- nehany modul mar meg van irva (akad koztuk olyan is amelyik zart es az API mar adott), ezeknel ki kellene mappelni az uj API-t, ami workaround2 lesz a workaround1-ra + vesztett teljesitmeny...
- szeretem ugy tervezni az API-kat, hogy az kifele transzparens legyen az en belso "nyugjeimtol"
- szeretem ha egy szoftver vilagos, attekintheto, egyseges API-val rendelkezik mindenutt, (lehetosegekhez merten) mert akkor nem kell feltalalni ketszer az orvossagot ugyanazon problemakra :-)
- maximalista vagyok: jobban erdekel az ismeretlen megismerese, mint az elrejtesenek modja :-)
- egyeb okokbol nem tudok aludni, de ha tudnek akkor se tudnek emiatt. :-)
Az IDisposable-tol azert felek, mert ez elore nem volt bekalkulalva, de ha leszarmaztatom ebbol is, halvany fogalmam sincs, hogy milyen biztonsagi/egyeb hibak kerulhetnek elo a kesz modulokban amik tervezes elott nem voltak szamitasba veve. Mindenesetre nem vetettem el teljesen, de tartok tole.
"Szinte biztos, hogy létezik rá bejáratott, szép tervezési minta."
Remelem, hogy igazad van. :-)
Talaltam egyebkent meg mas hasonlo fogos problemat is pl. ami mas nyelvekben szinte de facto szabvanykent van kezelve: a "typedef". Nem lehet forditasi idoben tipusbehelyettesitest vegezni. Futas idoben kiertekeltet lehet, a referencia konyv szeint, ha leszarmaztatom a tipust (ami esetenkent minimalis performancia vesztessel is jarhat). De pl. egy System.UInt16 egyaltalan nem szarmaztathato le, mivel "sealed"-kent van deklaralva (mondjuk tudomanyos alkalmazasokban kulonosen agyrem lehet). Lehet, hogy nincs igazam, de en nem jottem meg ra a megfejtesere ennek sem. :-(
Minél korszakalkotóbb ötlettel állsz elő, annál több hülyén kell átverekedned magadat.
- A hozzászóláshoz be kell jelentkezni
A kivétellel még mindig nem értem mi a baj. Ha mondjuk az ősösztály konstruktorában dobsz ellenőrzetlen kivételt (ami Javában a RuntimeException, C#-ban elfelejtettem mi, mert azt rég hsználtam), akkor a származtatott osztályok kódjában semmit nem kell miatta átírni (csak ott, ahol további ellenőrzést is végzel). A példányosításkor kell rá figyelni, pont ahogy sng- írta. Ha exceptiönt kezelő nyelvet használsz, akkor általában illik a nem normális lefutást exceptiönnel jelezni.
Az IDisposeable interfészt akkor kell használni, ha virtuális gépen kívüli erőforrást kezel az ojjektumod. Például fájlt, vagy socketet. A leírásod alapján nem vagyok benne biztos, hogy ez a helyzet.
Bár még mindig nem teljesen világos, hogy mi a célod :-), pár dolog kezd világlani:
1. Az ojjektum maga "jön rá" a konstruktorban, ráadásul típusonként eltérő módon, hogy ő jogosult-e vagy nem, azaz az "overloaded" konstruktorból is dobhatunk kivételt. Azonban ezek közül már van, ami meg van írva, amibe nem tudunk belenyúlni, tehát nem világos, hogy ő hogy jelzi a saját esetleges jogosulatlanságát.
2. Egy keretrendszer dinamikusan tölti be az ojjektumokat, amiből sokféle van, tehát vélhetően valami katalógusból névszerinti osztálybetöltéssel.
3. Erőforráskezelés is van, azaz pontosan nyomon kell követni, hogy az erőforrás kezelésének jogát és kötelességét átvette-e az ojjektum, vagy nem.
Jól értem?
Amúgy én azt javaslom, hogy találd ki, hogy pontosan mi a funkció. Ehhez csinálj egy interfészt, amin mindennek világos jelentése van. Majd a már meglévő dolgokat wrappeld le, hogy ezt az interfészt megvalósítsák. Általában nem érdemes a teljesítményt hajhászni, főleg nem az átláthatóság árán. Arról nem is beszélve, hogy a teljesítmény leginkább a használt algoritmusokon múlik, nem azon, hogy hány ősosztály, meg runtime típusellenőrzés van.
- A hozzászóláshoz be kell jelentkezni
"Javában a RuntimeException, C#-ban elfelejtettem mi"
System.Exception :-)
1. Igen, az ojjektum inicializalaskor derul ki, hogy ez igy jo lesz avagy nem. :-)
Azonban ezek közül már van, ami meg van írva, amibe nem tudunk belenyúlni, tehát nem világos, hogy ő hogy jelzi a saját esetleges jogosulatlanságát.
Kifele sehogyan, belsoleg naplozza a hibas modult.
"2. Egy keretrendszer dinamikusan tölti be az ojjektumokat, amiből sokféle van, tehát vélhetően valami katalógusból névszerinti osztálybetöltéssel."
LDAP adatbazisbol. Amikor az LDAP kivalt egy meghatarozott eventet, akkor uj modul erkezett. :-)
3. Igen. :-)
"Általában nem érdemes a teljesítményt hajhászni, főleg nem az átláthatóság árán."
En is igy gondolom, nem is engedek a 21-bol, ha az API-t kel piszkalni. :-)
"Arról nem is beszélve, hogy a teljesítmény leginkább a használt algoritmusokon múlik, nem azon, hogy hány ősosztály, meg runtime típusellenőrzés van."
Ebben is egyet ertunk. :-)
Koszi a tanacsokat, megfogadom. :-)
Egyebkent az IDisposabe fele hajlok egyre jobban, mivel ezt az egyetlen esszeru modjat latom az API piszkalas elkerulesenek. Meg nem erett meg bennem, mert tenylegesen at kell gondolni, hogy nem fog-e ez valamivel utkozni ami korabban nem volt bekalkulalva. Majd lassan megerik bennem, addig ideiglenesen marad a static method-boli eloteszteles.
SZERK: jut eszembe, esetleg Java-ban ismersz hasonlo constructor-on beluli ellenorzest? Mert mar a topik bekuldese elott is az jart az eszemben, hogy ha van ra Java-s megoldas, azt meg lehetne problani egy intelligensebb java2csharp-pal atkonvertalni.
Minél korszakalkotóbb ötlettel állsz elő, annál több hülyén kell átverekedned magadat.
- A hozzászóláshoz be kell jelentkezni
SZERK: jut eszembe, esetleg Java-ban ismersz hasonlo constructor-on beluli ellenorzest? Mert mar a topik bekuldese elott is az jart az eszemben, hogy ha van ra Java-s megoldas, azt meg lehetne problani egy intelligensebb java2csharp-pal atkonvertalni.
A Java, meg a C# minden lényeges szempontból ugyanaz. Ráadásul mivel amit Javában írnál C#-ra fordulna, nincs értelme Javában megírni, megírhatod C#-ban is :-).
Amúgy még mindig nem világos nekem ez a "konstruktoron belüli" para. És még mindig azt mondom (bár eddig nem mondtam, csak gondoltam rá :-)), hogy ha kell dinamikusan osztályt betölteni, akkor álalában a Factory mintát szokás használni. ami kb így néz ki:
interface IMyFactory
{
// Ha exceptionnel jön vissza, akkor "szerződés szerint" a hívó fél dolga az erőforrás felszabadítása
IMyOjjekt createOjjekt(Object arg) throws CreationException;
}
interface IMyOjjekt
{
Object doTheJob();
void freeTheResources();
}
Vagy gondolhatsz a gyártott ojjektumra úgy is, mint valami sessiönre, amit mindenképp le kell zárni. A lényeg, hogy ha nem kényelmes kívülről a konstruktoros megoldás, akkor ne használd, hanem csinálj egy normális interfészt, a meglévőket meg igenis wrappeld le. Az IDisposeable csak annyi könnyebséget jelent, hogy használhatod a using nylevi konstrukciót (ami azonos a try{}finally{ojjekt.dispose();} konstrukcióval).
>>Azonban ezek közül már van, ami meg van írva, amibe nem tudunk belenyúlni, tehát nem >>világos, hogy ő hogy jelzi a saját esetleges jogosulatlanságát.
>Kifele sehogyan, belsoleg naplozza a hibas modult.
És naplózni elég? Az erőforráskezelést megoldja ez jól?
- A hozzászóláshoz be kell jelentkezni
Koszi a segitseget, kozben megoldodott. :-)
A factory pattern-nel is probaltam korabban (elfelejtettem mondani), sajnos ezzel is gubancok voltak, de menet kozben elojott egy masik problema a modul kontener oldalan, ami miatt invalid modul is felkerulhetett volna a modullistara, igy kenytelen voltam atfogobb ellenorzest tervezni hozza.
A fenti problema ugy oldodott meg, hogy a kontenert es a kontenerlistat szetvalasztottam egy masik problema folytan, igy a modulnak most van egy kulonallo "szerveroldali" hivoosztalya is, nem csak szerveroldali modullista. Most minden kontener inicializalja a hozzatartozo dinamikus guestet. Mivel igy ezeknek egy property-je a kulso modulra kell, hogy mutasson, mindenkeppen kell egy programresz ahol ez a property-be bekerul (set { KulsoOjjektum = new ojjektum(bemeno argumentumlista) } ). Na ennel a resznel oldottam meg a validaciot normalisan a try/catch dologgal, ahogy azt kell, nem pedig az eddigi kulsomodulban valo statikus metodus belso leszarmaztatasaval. Nem mondom, hogy maskepp ne lehetett volna, de igy tobb mas tenyezo miatt ez tunt a legkezenfekvobbnek.
Eroforraskezeles sem problema mar, mert a kvotazast es az eroforrasatadast a belso kontener biztositja minden kulso modul szamara, igy ha valid ojjektum nem jon letre a kontenerben, az eroforrasmegosztas el sem kezdodik kifele. :-)
Minél korszakalkotóbb ötlettel állsz elő, annál több hülyén kell átverekedned magadat.
- A hozzászóláshoz be kell jelentkezni