Hvilke typer til bruk for boksing i generics

stemmer
4

Jeg har skrevet en enkel abstrakt generisk klasse i C # (.NET 2.0) og jeg helst vil begrense det til bare referansetyper, slik at jeg kan indikere noen verdi av en null. Men jeg ønsker også å bruke typer som lang og desimal, hvorfor ikke la null (blir structs tross alt). Jeg vurderte å lage klassen

public abstract Field<Nullable<T>>
{

}

Men det ville hindre min bruk av strengen type, som er en klasse. Hvordan kan jeg boksen opp mine desimaler og lengter så jeg kan bruke dem i denne generisk.

 abstract class Field<T>
 {
    private int _Length = 1;
    private bool _Required = false;
    protected T _Value; //= null;

    public int Length
    {
        get { return _Length; }
        private set
        {
            if (value < 1) throw new ArgumentException(Field length must be at least one.);
            _Length = value;
        }
    }

    public bool Required
    {
        get { return _Required; }
        private set { _Required = value; }
    }

    public abstract string GetFieldValue();
    public abstract void ParseFieldValue(string s);

    public virtual T Value
    {
        get { return _Value; }
        set
        {
            if (value == null && Required)
                throw new ArgumentException(Required values cannot be null.);
            _Value = value;
        }
    }

}

Vær oppmerksom på at jeg trenger å representere tall 0 og null annerledes. Av denne grunn standard (T) vil ikke fungere.

Publisert på 12/05/2009 klokken 12:06
kilden bruker
På andre språk...                            


6 svar

stemmer
3

Hele poenget med generiske legemidler (blant andre) er å unngå boksing. Se dette :

private bool _Required = false;
protected T _Value = default(T);

Hvis du trenger å skille mellom "0" og "ikke satt", objecter den eneste veien ut:

protected object _Value;

Og så box-unbox-box-unbox.

Svarte 12/05/2009 kl. 12:08
kilden bruker

stemmer
2

Du ville trenge to klasser

abstract class FieldR<T> where T: class
{
  T Value { get {} set {} }
}

abstract class FieldV<T> where T: struct
{
  Nullable<T> Value { get {} set {} }
}

Den første klassen ville bruke

T

Mens andre klassen ville bruke

Nullable<T>
Svarte 12/05/2009 kl. 12:53
kilden bruker

stemmer
1

Jeg er ikke sikker på om du kan begrense den generiske parametere hensiktsmessig ved kompilering, men du kan legge inn noen runtime sjekker for å bare tillate referanse typer sammen med ønsket undergruppe av kan ha nullverdier verdityper:

public virtual T Value
{
    get { return _Value; }
    set
    {
        Type t = typeof(T);
        if (t.IsValueType)
        {
            if (t.IsGenericType
                && (t.GetGenericTypeDefinition() == typeof(Nullable<>)))
            {
                Type u = Nullable.GetUnderlyingType(t);
                if ((u != typeof(long)) && (u != typeof(decimal)))
                {
                    throw new ArgumentException(
                        "Only long? and decimal? permitted!");
                }
            }
            else
            {
                throw new ArgumentException("Only nullable types permitted!");
            }
        }

        if ((value == null) && Required)
        {
            throw new ArgumentException("Required values cannot be null!");
        }

        _Value = value;
    }
}

(I virkeligheten, vil du sannsynligvis ønske å sette din type kontroller i en konstruktør stedet Valuesetter.)

Svarte 12/05/2009 kl. 13:14
kilden bruker

stemmer
0

Jeg foreslår at man oppretter en klasse Holder <t> med en ubegrenset typen parameter T, som eksponerer et felt av typen T; det ville ha både en standard konstruktør, og en enkelt-argument konstruktør av type T. I tillegg kan det være lurt å definere et grensesnitt IReadableHolder <T>, som vil bli gjennomført ved Holder <T>, men som også kan gjennomføres ved en hvilken som helst klasse typene du define (en forekomst av klassen foo ville gjennomføre IReadableHolder <foo> ved å ha sin verdi eiendom avkastning selv, og dermed gir en rutine forventer en IReadableHolder <foo> for å godta enten Holder <foo> eller en foo selv. Synd det er ikke mulig å definere en "forlengelse grensesnitt" for å legge til en implementering av IHolder <String> til klassen String.

Svarte 27/08/2011 kl. 18:34
kilden bruker

stemmer
0

Det er et godt spørsmål. Jeg skulle ønske dette var mulig:

class MyClass<T> where T : struct {
    T? value;
    ...
}
class MyClass<T> where T : class {
    T value;
    ...
}

og kompilatoren ville velge riktig generisk klasse avhengig av om begrensningene er fornøyd.

Dessverre fungerer det ikke, noe som kan føre til problemer med automatisk kilde kodegenerering.

Svarte 12/05/2009 kl. 12:34
kilden bruker

stemmer
0

Prøv dette:

public abstract Field<T>
    where T : class
{

}

Dette vil begrense den generiske typen parameteren for å være en referansetype. Dette er den eneste måten du vil være i stand til å returnere nullfra denne metoden. Ja, dette vil hindre deg fra å passere verdityper til metoden.

Svarte 12/05/2009 kl. 12:08
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more