Frage

Ich frage mich, ob die folgende ist möglich. Erstellen Sie eine Klasse, die einen anonymen Typ akzeptiert (string, int, dezimal, customObject, etc), dann Methoden überlastet, die verschiedene Operationen ausführen basierend auf der Art. Beispiel

    class TestClass<T>
{
  public void GetName<string>()
  {
      //do work knowing that the type is a string    
  }

  public string GetName<int>()
  {
      //do work knowing that the type is an int

  } 

  public string GetName<int>(int addNumber)
  {
      //do work knowing that the type is an int (overloaded)    
  } 

  public string GetName<DateTime>()
  {
      //do work knowing that the type is a DateTime

  } 

  public string GetName<customObject>()
  {
      //do work knowing that the type is a customObject type    
  }

}

So, jetzt könnte ich die GetName-Methode aufrufen, und weil ich schon in der Art übergeben, wenn ich das Objekt initialisiert, wird die richtige Methode gefunden und ausgeführt werden.

TestClass foo = new TestClass<int>();

//executes the second method because that's the only one with a "int" type
foo.GetName();

Ist das möglich oder bin ich nur träumen?

War es hilfreich?

Lösung

Was Sie versuchen, ist möglich, wie dies zu tun:

class TestClass<T>
{
   public string GetName<T>()
   {
      Type typeOfT = typeof(T);
      if(typeOfT == typeof(string))
      {
          //do string stuff
      }
   }
}

Während dieses ist möglich, sind Sie Art von Sieg über den Zweck der Generika. Der Punkt von Generika ist, wenn der Typ nicht Materie, so dass ich glaube nicht, dass Generika ist angemessen, in diesem Fall.

Andere Tipps

Spezialisierung ist in C # nicht möglich. Die nächste Sache in C # ist die folgende

public void Example() {
  public static void Method<T>(T value) { ... }
  public static void Method(int value){ ... }
  public static void Method(string) { ... }
}

Die C # Compiler wird eine nicht-generische Methode über eine generische Methode bevorzugen. Dies bedeutet, dass mit einem int Aufruf Paramater zum int Überlastung gegen die generischen binden.

Example.Method(42);  // Method(int)
Example.Method(new Class1())  // Method<T>(T)

Das wird Sie aber beißen, weil dies gilt nicht, wenn das Verfahren allgemein genannt wird. In diesem Fall wird es an die allgemeinen Überlastung bindet unabhängig von der Art.

public void Gotcha<T>(T value) {
  Example.Method(value);
}

Gotcha(42);  // Still calls Example.Method<T>()

"Spezialisierung" ist nicht möglich, in C # so, wie es in C ++. In .NET Generika, einer generischen Klasse oder Methode von muss für alle möglichen Werte von T. sein Dies ist die Laufzeit ermöglicht eine Optimierung, die zwei verschiedene Referenztypen zu tun, sagen Testclass und Testclass >, teilen sich die gleiche Maschinensprachcode. (Verschiedene Werttypen separaten Maschinencode, aber man kann immer noch nicht gehört.)

Ich finde es manchmal eine generische Schnittstelle oder Basisklasse wie diese erstellen hilft:

abstract class Base<T> {
  public abstract T GetName();
  // any common code goes here that does not require specialization
}

Und tut Spezialisierung in abgeleiteten Klassen:

class IntVersion : Base<int> {
  public override int GetName() { return 1; }
  public int GetName(int addNumber) { ... }
}
class StringVersion : Base<string> {
  public override string GetName() { return "foo"; }
}
class DateTimeVersion : Base<DateTime> {
  public override DateTime GetName() { return DateTime.Now; }
}

Nein, das ist nicht möglich. Was Sie versuchen, ist ähnlich wie Template-Spezialisierung in C ++ zu tun, die (leider) nicht möglich, in C # ist.

Sie müssen if / else oder einschalten

typeof(T)

spezielle Implementierungen aufzurufen.

Sie können jedoch die Art des T Zwang entweder eine Klasse (Referenzwert) oder Struktur (Wert) oder Unterklasse einer bestimmten Basisklasse wie so zu sein:

 public Foo<T> DoBar<T>() where T : FooBase;

c # haben keine Unterstützung für solche Disposition.

und das ist nicht richtig auch Verfahren Überlastung zu tun (Error'TestClass' definiert bereits ein Mitglied namens ‚GetName‘ mit den gleichen Parametertypen), solange alle innerhalb von <> ist nicht ein Teil der Methodensignatur.

Möchten mit Klasse Erweiterungsmethoden für Sie arbeiten?

Sie können im Wesentlichen Hinzufügen von Methoden zu den Klassen, die Sie wollen, und dann können Sie es auf die gleiche Weise nennen.

namespace ExtensionMethods
{
    public static class MyExtensions
    {
        public static int GetName(this String str)
        {
            ...
        }
    }   
}

genannt werden:

myString.GetName();

Wenn Sie typspezifische Arbeit in der Klasse zu tun, dann ist Ihre Klasse nicht generisch. Sie sollten wahrscheinlich eine separate Klasse für jeden Typ, den Sie behandeln möchten machen. Wenn es einige Funktionen, die für Gattungs einen richtigen Grund haben, können Sie es in einer gemeinsamen Basisklasse setzen.

Ein Beispiel:

abstract class TestClass<T>
{
    public List<T> Items { get; set; }

    // other generic (i.e. non type-specific) code
}

class IntTestClass : TestClass<int>
{
    public string GetName()
    {
        // do work knowing that the type is an int
    }

    // other code specific to the int case
}

class StringTestClass : TestClass<string>
{
    public string GetName()
    {
        // do work knowing that the type is a string
    }

    // other code specific to the string case
}

Wie BFree erwähnte man dies mit einem tun können, wenn Baum, oder eher eine switch-Anweisung, aber irgendwann werden Sie wollen Sie nur Methoden schreiben könnten und lassen .Net es herausfinden, vor allem, wenn Sie die Bibliothek wachsen von Überlastungen im Laufe der Zeit.

Die Lösung gibt es Reflexion, obwohl es ziemlich billig leistungsmäßig in .Net ist:

using System.Reflection;
...

public string DoSomething(object val)
{
    // Force the concrete type
    var typeArgs = new Type[] { val.GetType() };

    // Avoid hard-coding the overloaded method name
    string methodName = new Func<string, string>(GetName).Method.Name;

    // Use BindingFlags.NonPublic instead of Public, if protected or private
    var bindingFlags = BindingFlags.Public | BindingFlags.Instance;

    var method = this.GetType().GetMethod(
        methodName, bindingFlags, null, typeArgs, null);

    string s = (string)method.Invoke(this, new object[] { val });

    return s;
}

Sie sagen im Grunde nur die Reflexion Rahmen für Sie, dass switch-Anweisung zu gehen tun.

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