Frage

Gibt es eine Möglichkeit, die an Grundelemente übergebenen Typen zu erzwingen/einschränken? (bool, int, string usw.)

Jetzt weiß ich, dass Sie den generischen Typparameter über die auf eine Typ- oder Schnittstellenimplementierung beschränken können Wo Klausel.Dies entspricht jedoch nicht der Rechnung für Grundelemente (AFAIK), da sie nicht alle eine gemeinsame Basis haben (außer Objekt bevor es jemand sagt!:P).

Daher denke ich derzeit darüber nach, einfach die Zähne zusammenzubeißen und etwas Großes zu leisten schalten Aussage und wirf eine ArgumentException beim Scheitern..


EDIT 1:

Nur um klarzustellen:

Die Codedefinition sollte wie folgt aussehen:

public class MyClass<GenericType> ....

Und Instanziierung:

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!)

BEARBEITEN 2

@Jon Limjap – Guter Punkt und etwas, über das ich bereits nachgedacht habe.Ich bin sicher, dass es eine generische Methode gibt, mit der festgestellt werden kann, ob es sich bei dem Typ um einen Wert- oder Referenztyp handelt.

Dies könnte nützlich sein, um viele der Objekte, mit denen ich mich nicht befassen möchte, sofort zu entfernen (aber dann müssen Sie sich um die verwendeten Strukturen kümmern, z. B Größe )..Interessantes Problem, nein?:) :)

Hier ist es:

where T : struct

Genommen von MSDN.


Ich bin neugierig..Könnte dies in .NET 3.x mithilfe von Erweiterungsmethoden erfolgen?Erstellen Sie eine Schnittstelle und implementieren Sie die Schnittstelle in den Erweiterungsmethoden (was wahrscheinlich sauberer wäre als ein etwas fetter Schalter).Und wenn Sie später auf beliebige leichtgewichtige benutzerdefinierte Typen erweitern müssen, können diese auch dieselbe Schnittstelle implementieren, ohne dass Änderungen am Basiscode erforderlich sind.

Was denkt ihr?

Die traurige Nachricht ist, dass ich in Framework 2 arbeite!!:D


BEARBEITEN 3

Das war so einfach im Anschluss daran Jon Limjaps Zeiger..So einfach, dass ich fast weinen möchte, aber es ist großartig, weil der Code wie ein Zauber funktioniert!

Also hier ist, was ich getan habe (Sie werden lachen!):

Der generischen Klasse hinzugefügter Code

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;
    }
}

Dann eine kleine Hilfsmethode, um den Typ zu überprüfen und eine Ausnahme auszulösen.

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.");
}

Dann müssen Sie nur noch anrufen EnforcePrimitiveType() in den Klassenkonstruktoren.Job erledigt!:-)

Der einzige Nachteil ist, dass es (offensichtlich) nur zur Laufzeit und nicht zur Entwurfszeit eine Ausnahme auslöst.Aber das ist keine große Sache und könnte von Energieversorgern übernommen werden FxCop (was wir bei der Arbeit nicht verwenden).

Besonderer Dank geht hier an Jon Limjap!

War es hilfreich?

Lösung

Primitive scheinen in der spezifiziert zu sein TypeCode Aufzählung:

Vielleicht gibt es eine Möglichkeit herauszufinden, ob ein Objekt das enthält TypeCode enum ohne es in ein bestimmtes Objekt oder einen bestimmten Aufruf umwandeln zu müssen GetType() oder typeof()?

Aktualisieren Es war direkt vor meiner Nase.Das dortige Codebeispiel zeigt Folgendes:

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;
        }
    }
}

Es ist immer noch ein hässlicher Schalter.Aber es ist ein guter Anfang!

Andere Tipps

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

Dieser schien den Job zu machen.

So ziemlich das, was @Lars bereits gesagt hat:

//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()

Alle funktionieren in .NET 2, 3 und 3.5.

Wenn Sie die Verwendung von Factory-Methoden (anstelle der von Ihnen gewünschten Konstruktoren MyClass) tolerieren können, können Sie jederzeit Folgendes tun:

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
}

Ein Problem hierbei ist, dass Sie tippen müssten MyClass<AnyTypeItDoesntMatter>.FromInt32, was ärgerlich ist.Es gibt keinen sehr guten Weg, dies zu umgehen, wenn Sie die Privatsphäre des Konstruktors aufrechterhalten möchten, aber hier sind ein paar Problemumgehungen:

  • Erstellen Sie eine abstrakte Klasse MyClass.Machen MyClass<T> geerbt von MyClass und verschachtele es darin MyClass.Verschieben Sie die statischen Methoden nach MyClass.Dadurch wird die gesamte Sichtbarkeit gewährleistet, allerdings auf Kosten des Zugriffs MyClass<T> als MyClass.MyClass<T>.
  • Verwenden MyClass<T> wie gegeben.Erstellen Sie eine statische Klasse MyClass die die statischen Methoden aufruft MyClass<T> verwenden MyClass<AnyTypeItDoesntMatter> (wahrscheinlich jedes Mal den passenden Typ verwenden, nur zum Kichern).
  • (Einfacher, aber sicherlich seltsam) Erstellen Sie einen abstrakten Typ MyClass was erbt von MyClass<AnyTypeItDoesntMatter>.(Der Konkretheit halber sagen wir mal MyClass<int>.) Da Sie statische Methoden, die in einer Basisklasse definiert sind, über den Namen einer abgeleiteten Klasse aufrufen können, können Sie sie jetzt verwenden MyClass.FromString.

Dadurch erhalten Sie eine statische Überprüfung, müssen aber mehr schreiben.

Wenn Sie mit der dynamischen Prüfung zufrieden sind, würde ich eine Variation der oben genannten TypeCode-Lösung verwenden.

@Rauben, Enum's wird durch die schlüpfen TypeValid funktionieren wie es ist TypeCode Ist Integer.Ich habe die Funktion aktualisiert, um auch nach zu suchen 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

Sie können das vereinfachen EnforcePrimitiveType Methode durch Verwendung typeof(PrimitiveDataType).IsPrimitive Eigentum.Vermisse ich etwas?

Verwenden Sie eine benutzerdefinierte FxCop Regel, die unerwünschte Verwendung von kennzeichnet MyClass<>.

Da ich vor einer ähnlichen Herausforderung stehe, frage ich mich, was ihr davon denkt IConvertible-Schnittstelle.Es ermöglicht, was der Anforderer benötigt, und Sie können es mit Ihren eigenen Implementierungen erweitern.

Beispiel:

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

Ich denke darüber nach, dies als Lösung zu sehen, obwohl viele der Vorschläge auch Teil meiner Auswahl waren.

Ich mache mir jedoch Sorgen, ob es für potenzielle Entwickler, die Ihre Klasse verwenden, irreführend ist.

Prost – und Danke.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top