Generics vs. nullable value types

Tento problém sa mi vybavil Pri vlkovej správičke Čo Vás srdí na .NET .Povedzme teda, že máme zápis funkcie, ktorú chceme urobiť univerzálnou pre všetky nullable value types.

public static Func<int?, int?, bool> func1 = (x, y) => (x != null && y != null && x > y);
resp.
public delegate bool DelFunc<T>(T x, T y);
public static DelFunc<int?> funct11 = (x, y) => (x != null && y != null && x > y);

Tieto dva nápady samozrejme nie sú cestou:

public static bool func2<T>(T x, T y)
    where T: Nullable<T>() 
{
//...
}


public static bool func3<T>(T x, T y)
where T: IComparable
{
    return (x != null && y != null && x.CompareTo(y) > 0);
}

Prvý nepôjde skompilovať. Vynútiť si len nullable typy sa nedá. Druhý nezafunguje preto, že nullable typy neimplementujú IComparable - len ich ne-nullable verzie. Je to by design rozhodnutie. Porovnanie väčší/menší medzi null a hodnotou pri value types je z logického hľadiska nezmyslom - nemôžete porovnávať niečo, čo hodnotu nemá s niečim, čo ju má. Samozrejme v praxi pristupujeme aj ku tomuto "nezmyslu" a pre to porovnanie máme vlastnú interpretáciu. Čiže - musíme to vždy obkódovať.(niektoré jazyky umožňujú definovať logiku týchto porovnaní)

Existuje cesta? Povedzme že ...

public static bool func5<T>(T x, T y)            
{
    return (x != null && y != null && ((IComparable)x).CompareTo(y) > 0);
}

...ale je to naozaj dobrá cesta a prínos? Strácame type safety pre našu funkciu, čo malo byť zmyslom použitia genericsov, snáď len typová kontrola medzi oboma parametrami je malým prínosom. (IComparable) valueType boxuje a volanie CompareTo znova. Pri funkciách podobného typu nad value typeami je toto správanie maximálne nevhodné a podľa mňa čistejším ekvivalentom je potom táto verzia:

public static bool func6(IComparable x, IComparable y)
{
    return (x != null && y != null && x.CompareTo(y) > 0);
}

Používateľovi funkcie je jasné, že ku boxovaniu príde(urobí ho on) a žiadna hlávka pri rozširovaní výrazov vo funkcii nezabudne na to, že boxing sa udeje pri každom pretypovaní na IComparable a teda nebude všade v jej tele robiť inline pretypovanie.

Komentáre

# vlko said:

ked ti ide o nullable, preco nepouzijes nieco taketo:

public static bool func2<T>(Nullable<T> x, Nullable<T> y)

{

return (x != null && y != null && x.Value.Equals(y));

}

static void Main(string[] args)

{

int? x = 1;

int? y = null;

bool compare = func2(x, y);

Thursday, February 05, 2009 12:44 PM
# vlko said:

sorry zabudol som doplnit T podmienku:

public static bool func2<T>(Nullable<T> x, Nullable<T> y) where T : struct

{

return (x != null && y != null && x.Value.Equals(y));

}

static void Main(string[] args)

{

int? x = 1;

int? y = null;

bool compare = func2(x, y);

Thursday, February 05, 2009 12:48 PM
# T said:

Vdaka, Vlko, vdaka, vdaka....za preliecenie...

..... teraz sa hanbim, ze som si uveril, ze to nejde a vymyslal:-)

T? -> Nullable<T> takto este krajsie...

public static bool func2<T>(T? x, T? y) where T : struct

Thursday, February 05, 2009 4:44 PM
# vlko said:

rado sa stalo, to este nic nebolo, tot nedavno som mal zaujimavy blog prispevok: blog.vyvojar.cz/.../ako-narva-generick-triedy-do-kolekcie.aspx

Thursday, February 05, 2009 5:09 PM
Prihlásiť | Registrovať | Pomoc