Verfahren Overloading mit Typen C #
-
05-07-2019 - |
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?
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 >, 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.