13 Stimmen

Typisierung allgemeiner Werte (C#)

Wenn ich dies mit einer generischen Klasse versuche, bei der this.value T ist:

if (this.value.GetType() == typeof(int))
{
    ((int)this.value)++;
}
else
{
    throw new InvalidOperationException
            ("T must be an int to perform this operation");
}

Ich erhalte einen Kompilierzeitfehler: "Der Typ 'T' kann nicht in 'int' konvertiert werden".

Was sollte ich tun, um eine Integraloperation auf this.value durchzuführen, wenn es ein int ist?

Beachten Sie, dass dies nur ein Beispiel ist. Der Code führt Typkonvertierungen mit Generika durch, und "int" ist nur ein Beispiel für einen Typ für T.

24voto

Marc Gravell Punkte 970173

Leider ist es sehr schwer, den Compiler von bestimmten T-Implementierungen zu überzeugen. Ein (unangenehmer) Ansatz besteht darin, in der Mitte in ein Objekt zu casten (beachten Sie, dass dadurch Wertetypen ge- und entpackt werden):

int i = (int)(object)this.value;
i++;
this.value = (T)(object)i;

Hässlich, aber es funktioniert. In .NET 3.5 habe ich einige bessere Wrapper für generische Arithmetik, aquí . Die Klasse Operator ist Teil von MiscUtil Ich vermute, dass AddAlternative auf der einfachsten Ebene sehr gut funktionieren würde:

this.value = Operator.AddAlternative(this.value, 1);

Dies sollte die impliziten <T,int> automatisch herleiten, oder Sie können sie selbst hinzufügen:

this.value = Operator.AddAlternative<T,int>(this.value, 1);

Nutzen Sie : Dies ist dem ursprünglichen Code vorzuziehen, da er sich nicht um das ursprüngliche T kümmert - er funktioniert für jeden Typ (auch Ihren eigenen), der "T +(T,int)" unterstützt.

Ich glaube, irgendwo da drin ist auch ein ChangeType versteckt...

[Collin K und andere machen eine gültige Bemerkung über die architektonischen Implikationen - aber da ich pragmatisch bin, gibt es Zeiten, in denen das T wirklich so wichtig ist... aber ich würde zustimmen, diese Art von Spezialisierung zu vermeiden, es sei denn, es gibt einen anderen Weg. vraiment notwendig. Abgesehen davon (wie in meinem Kommentar zu Collins Beitrag) ist die Fähigkeit, Dinge wie grundlegende Arithmetik (Inkrement, Int32-Division usw.) auf (zum Beispiel) einer Matrix<T> [für T in dezimal/float/int/double/etc] durchzuführen, oft sehr wertvoll.

12voto

Collin K Punkte 14788

Meiner Meinung nach ist typspezifischer Code in einer generischen Klasse ein Codegeruch. Ich würde sie umstrukturieren, um etwas wie dies zu erhalten:

public class MyClass<T>
{
 ...
}

public class IntClass : MyClass<int>
{
  public void IncrementMe()
  {
    this.value++;
  }
}

3voto

Ilya Ryzhenkov Punkte 11342

Die statische Typisierung von C# lässt dies nicht zu, aber man kann sie mit dem Casting auf Objekt überlisten. Ich würde nicht empfehlen, dies zu tun, es zeigt wahrscheinlich architektonische Problem, aber trotzdem:

using System;

class Foo<T>
{
  public T value;

  public void Increment()
  {
   if (value is int) value = (T)(object)(((int)(object)value)+1);
  }
}

static class Program
{
    static void Main()
    {
     Foo<int> x = new Foo<int>();
     x.Increment();
     x.Increment();
      Console.WriteLine(x.value); 
    }     
}

0voto

user25306 Punkte 411

Ich glaube, ich verstehe nicht, worauf Sie hinauswollen. Wenn Sie verlangen, dass etwas ein bestimmter Typ ist, dann sollten Sie wahrscheinlich nicht Generics verwenden. Sie könnten, es scheint nur dumm. Dies wird tun, was Sie fragen, aber ich empfehle es nicht.

namespace GenericsOne
{
    using System;

class Program
{
    static void Main(string[] args)
    {
        Sample<int> one = new Sample<int>();
        one.AddFive(10);

        // yes, this will fail, it is to show why the approach is generally not a good one.
        Sample<DateTime> two = new Sample<DateTime>();
        two.AddFive(new DateTime());
    }
}

}

namespace GenericsOne
{
    using System;
public class Sample<T>
{
    public int AddFive(T number)
    {
        int junk = 0;

        try
        {
            junk = Convert.ToInt32(number);
        }
        catch (Exception)
        {
            Console.WriteLine("Nope");
        }

        return junk + 5;
    }
}
}

0voto

Keith Punkte 141163

Deshalb möchte ich wirklich numerische oder operationelle Beschränkungen in C#4 .

Die Antwort von @Marc Gravell ist der beste Weg, dies zu umgehen (+1), aber es ist frustrierend, wie dies ein Problem für Generika ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X