Domanda

Esiste un modo per imporre/limitare i tipi passati alle primitive? (bool, int, stringa, ecc.)

Ora, so che puoi limitare il parametro di tipo generico a un'implementazione di tipo o interfaccia tramite il file Dove clausola.Tuttavia, questo non si adatta al conto dei primitivi (AFAIK) perché non hanno tutti un terreno comune (a parte oggetto prima che qualcuno lo dica!:P).

Quindi, il mio pensiero attuale è semplicemente stringere i denti e fare un grande interruttore dichiarazione e lanciare un ArgumentException in caso di fallimento..


MODIFICA 1:

Giusto per chiarire:

La definizione del codice dovrebbe essere come:

public class MyClass<GenericType> ....

E istanziazione:

MyClass<bool> = new MyClass<bool>(); // Legal
MyClass<string> = new MyClass<string>(); // Legal
MyClass<DataSet> = new MyClass<DataSet>(); // Illegal
MyClass<RobsFunkyHat> = new MyClass<RobsFunkyHat>(); // Illegal (but looks awesome!)

MODIFICA 2

@Jon Limjap - Giusta osservazione, ed è qualcosa che stavo già considerando...Sono sicuro che esista un metodo generico che può essere utilizzato per determinare se il tipo è di valore o di riferimento.

Questo potrebbe essere utile per rimuovere istantaneamente molti oggetti di cui non voglio occuparmi (ma poi devi preoccuparti delle strutture utilizzate come Misurare )..Problema interessante, no?:)

Ecco qui:

where T : struct

Preso da MSDN.


Sono curioso..È possibile eseguire questa operazione in .NET 3.x utilizzando metodi di estensione?Creare un'interfaccia e implementarla nei metodi di estensione (che probabilmente sarebbe più pulito di un cambio un po' grosso).Inoltre, se in seguito è necessario estenderlo a qualsiasi tipo personalizzato leggero, è anche possibile implementare la stessa interfaccia, senza che siano necessarie modifiche al codice di base.

Che cosa ne pensate?

La triste notizia è che sto lavorando nel Framework 2!!:D


MODIFICA 3

Questo è stato così semplice da seguire Puntatore di Jon Limjaps..Così semplice che mi viene quasi da piangere, ma è fantastico perché il codice funziona a meraviglia!

Quindi ecco cosa ho fatto (riderai!):

Codice aggiunto alla classe generica

bool TypeValid()
{
    // Get the TypeCode from the Primitive Type
    TypeCode code = Type.GetTypeCode(typeof(PrimitiveDataType));

    // All of the TypeCode Enumeration refer Primitive Types
    // with the exception of Object and Empty (Null).
    // Since I am willing to allow Null Types (at this time)
    // all we need to check for is Object!
    switch (code)
    {
        case TypeCode.Object:
            return false;
        default:
            return true;
    }
}

Quindi un piccolo metodo di utilità per verificare il tipo e lanciare un'eccezione,

private void EnforcePrimitiveType()
{
    if (!TypeValid())
        throw new InvalidOperationException(
            "Unable to Instantiate SimpleMetadata based on the Generic Type of '" + typeof(PrimitiveDataType).Name + 
            "' - this Class is Designed to Work with Primitive Data Types Only.");
}

Allora non resta che chiamare ApplicaPrimitiveType() nei costruttori delle classi.Lavoro fatto!:-)

L'unico aspetto negativo è che genera un'eccezione solo in fase di esecuzione (ovviamente) anziché in fase di progettazione.Ma questo non è un grosso problema e potrebbe essere risolto con utilità come FxCop (che non usiamo al lavoro).

Un ringraziamento speciale a Jon Limjap per questo!

È stato utile?

Soluzione

Le primitive sembrano essere specificate in TypeCode enumerazione:

Forse c'è un modo per scoprire se un oggetto contiene il file TypeCode enum senza doverlo lanciare su un oggetto o una chiamata specifici GetType() O typeof()?

Aggiornamento Era proprio sotto il mio naso.L'esempio di codice mostra questo:

static void WriteObjectInfo(object testObject)
{
    TypeCode    typeCode = Type.GetTypeCode( testObject.GetType() );

    switch( typeCode )
    {
        case TypeCode.Boolean:
            Console.WriteLine("Boolean: {0}", testObject);
            break;

        case TypeCode.Double:
            Console.WriteLine("Double: {0}", testObject);
            break;

        default:
            Console.WriteLine("{0}: {1}", typeCode.ToString(), testObject);
            break;
        }
    }
}

È ancora un brutto cambiamento.Ma è un buon punto di partenza!

Altri suggerimenti

public class Class1<GenericType> where GenericType : struct
{
}

Questo sembrava fare il suo lavoro..

Più o meno quello che ha già detto @Lars:

//Force T to be a value (primitive) type.
public class Class1<T> where T: struct

//Force T to be a reference type.
public class Class1<T> where T: class

//Force T to be a parameterless constructor.
public class Class1<T> where T: new()

Funzionano tutti in .NET 2, 3 e 3.5.

Se riesci a tollerare l'utilizzo dei metodi factory (invece dei costruttori MyClass che hai richiesto) potresti sempre fare qualcosa del genere:

class MyClass<T>
{
  private readonly T _value;

  private MyClass(T value) { _value = value; }

  public static MyClass<int> FromInt32(int value) { return new MyClass<int>(value); }
  public static MyClass<string> FromString(string value) { return new MyClass<string>(value); }
  // etc for all the primitive types, or whatever other fixed set of types you are concerned about
}

Un problema qui è che dovresti digitare MyClass<AnyTypeItDoesntMatter>.FromInt32, il che è fastidioso.Non esiste un ottimo modo per aggirare questo problema se si desidera mantenere la riservatezza del costruttore, ma ecco un paio di soluzioni alternative:

  • Crea una classe astratta MyClass.Fare MyClass<T> ereditare da MyClass e annidarlo all'interno MyClass.Sposta i metodi statici in MyClass.In questo modo tutta la visibilità funzionerà, a costo di dover accedere MyClass<T> COME MyClass.MyClass<T>.
  • Utilizzo MyClass<T> come dato.Crea una classe statica MyClass che richiama i metodi statici MyClass<T> utilizzando MyClass<AnyTypeItDoesntMatter> (probabilmente usando ogni volta il tipo appropriato, solo per ridere).
  • (Più facile, ma certamente strano) Crea un tipo astratto MyClass da cui eredita MyClass<AnyTypeItDoesntMatter>.(Per concretezza, diciamo MyClass<int>.) Poiché è possibile chiamare metodi statici definiti in una classe base tramite il nome di una classe derivata, ora è possibile utilizzare MyClass.FromString.

Questo ti dà il controllo statico a scapito di più scrittura.

Se sei soddisfatto del controllo dinamico, utilizzerei qualche variazione sulla soluzione TypeCode sopra.

@Rapinare, Enumscivolerà attraverso il TypeValid funzionare così com'è TypeCode È Integer.Ho aggiornato anche la funzione per controllare Enum.

Private Function TypeValid() As Boolean
    Dim g As Type = GetType(T)
    Dim code As TypeCode = Type.GetTypeCode(g)

    ' All of the TypeCode Enumeration refer Primitive Types
    ' with the exception of Object and Empty (Nothing).
    ' Note: must also catch Enum as its type is Integer.
    Select Case code
        Case TypeCode.Object
            Return False
        Case Else
            ' Enum's TypeCode is Integer, so check BaseType
            If g.BaseType Is GetType(System.Enum) Then
                Return False
            Else
                Return True
            End If
    End Select
End Function

Puoi semplificare il EnforcePrimitiveType metodo utilizzando typeof(PrimitiveDataType).IsPrimitive proprietà.Mi sto perdendo qualcosa?

Usa un'abitudine FxCop regola che segnala l'uso indesiderato di MyClass<>.

Avendo una sfida simile, mi chiedevo come vi sentiste riguardo al Interfaccia IConvertibile.Consente ciò che richiede il richiedente e puoi estenderlo con le tue implementazioni.

Esempio:

    public class MyClass<TKey>
    where TKey : IConvertible
{
    // class intentionally abbreviated
}

Sto pensando a questa come a una soluzione, anche se molti dei suggerimenti facevano parte della mia selezione.

La mia preoccupazione è, tuttavia, che sia fuorviante per i potenziali sviluppatori che utilizzano la tua classe?

Saluti e grazie.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top