Frage

Wie kann ich die gute Methode wählen (ich habe im Beispiel unten zeigen 2 differents Art und Weise, die nicht funktioniert). Ich wurde anstelle einer Variablen vom Typ Object mit einem IF und IS die Arbeit zu tun, aber ich versuche mit Object und Boxen / Unboxing zu vermeiden. Also dachte ich, dass Generika könnte die Arbeit tun, aber ich bin hier fest.

Hier ist ein kleiner Ausschnitt aus Code, der meine Frage verdeutlichen:

class Program
{
    static void Main(string[] args)
    {
        Parser p = new Parser();
        ObjectType1 o1 = new ObjectType1();
        p.execute(o1);
        Console.Read();
    }
}

class Parser
{
    public T execute<T>(T obj)
    {
        /*
        if (obj is ObjectType1)
            this.action((ObjectType1)obj);
        else if (obj is ObjectType2)
            this.action((ObjectType2)obj);
        */
        this.action(obj);
        return obj;
    }

    private void action(ObjectType1 objectType1)
    {
        Console.WriteLine("1");
    }

    private void action(ObjectType2 objectType2)
    {
        Console.WriteLine("2");
    }
}


class ObjectType1
{
}

class ObjectType2
{
}

Update

Ich will nicht Schnittstelle und Klasse. Es tut uns leid. Ich wusste, dass es nicht das Ziel der Frage ist.

Casting mit (Objecttype) obj nicht funktioniert, aber wenn Sie tun:

        if (obj is ObjectType1)
            this.action(obj as ObjectType1);
        else if (obj is ObjectType2)
            this.action(obj as ObjectType1);

es funktioniert ... warum?

Und ... Ich kann nicht für alle Arten Überlastung des Verfahrens ausgeführt werden, da diese Methode von einer Schnittstelle ist. Aus diesem Grund alle brauchen von dieser Methode aufgerufen werden.

War es hilfreich?

Lösung

Nein, Sie können das nicht. Generics arbeiten nicht wie C ++ Vorlagen - die generische Methode wird nur einmal zusammengestellt. Die einzige Information, dass der Compiler für die Überladungsauflösung verwenden kann, ist die Informationen, die sie über in der generischen Methode kennen, unabhängig davon, welchen Code verwendet es.

Als Beispiel dies zu zeigen, hier ist ein Stück Code, die möglicherweise nicht, wie Sie es erwarten:

using System;

class Test
{    
    static void Main()
    {
        string x = "hello";
        string y = string.Copy(x);

        Console.WriteLine(x==y); // Overload used
        Compare(x, y);
    }

    static void Compare<T>(T x, T y) where T : class
    {
        Console.WriteLine(x == y); // Reference comparison
    }
}

Es ist schwer, die beste Art und Weise zu sagen, ohne zu wissen, um mehr darüber zu gehen, was Sie tun wollen.

Andere Tipps

Haben Sie Schnittstellen in Betracht gezogen?

interface IAction
{
   void action();
}

class ObjectType1 : IAction
{
   void action() {
      Console.WriteLine("1");
   }
}

class ObjectType2 : IAction
{
    void action() {
      Console.WriteLine("2");
    }
}

class Parser
{
   public IAction execute(IAction obj)
   {
      obj.action();
      return obj;
   }
}

Herausgegeben von OP:

Diese Lösung würde erfordern, dass alle Business-Logik-Objekt zu ändern, um diese Schnittstelle zu haben. Das ist wirklich kein Ding (in meiner Situation) zu tun. Und in der anderen Situation, ziehe ich es immer sauber Businessobject zu haben, die nicht-Schnittstelle verfügt nicht mit Geschäftsmaterial bezogen. In meiner Frage, ich mag eine Lösung, die mehr im Zusammenhang mit Universal / Objekt / Delegate-Methode ist es zu erreichen. Dank dir. Diese Antwort wird nicht akzeptiert.

  

Die Klasse Parser haben viele private Methode, die durch das Verfahren ausführt aufgerufen werden, abhängig vom Objekttyp. Es muss die gute Methode umleiten.

Der Compiler wird diese Arbeit für Sie tun. Verwenden Sie einfach Überlastung.

class Parser
{
    public ObjectType1 action(ObjectType1 objectType1)
    {
        Console.WriteLine("1");
        return objectType1;
    }
    public ObjectType2 action(ObjectType2 objectType2)
    {
        Console.WriteLine("2");
        return objectType2;
    }
}

class ObjectType1 { }
struct ObjectType2 { }

Dann rief mit:

Parser p = new Parser();
p.action(new ObjectType1());
p.action(new ObjectType2());

Es gibt keine Boxen / Unboxing und die entsprechende Methode aufgerufen wird.

Ich habe es nicht ausprobiert, aber können Sie tun?

public T execute<T>(T obj)
{
    this.action((T)obj);
    return obj;
}

(nach Kommentaren, funktioniert nicht)

oder

public T execute<T>(T obj)
{
    this.action(obj as T);
    return obj;
}

(nach Kommentaren, arbeitet)

Ich weiß, dass Sie besorgt sind über das Boxen / Unboxing, so könnte es ValueTypes hier einbezogen werden.

public T execute<T>(T obj)   
{        
    this.action(obj);
    return obj;
}

Angenommen, Aktion obj wird modifiziert, und unter der Annahme auch , die Änderung ist wichtig für den Anrufer (weshalb Sie den Wert sind Rückkehr an den Anrufer zurück). Dieser Code hat einen fiesen Pass-by-Wert Defekt.

Betrachten Sie diesen Code ein:

    public int execute(int obj)   
    {        
        this.action(obj);
        return obj;
    }

    public void action(int obj)
    {
        obj = obj + 1;
    }

auf diese Weise aufgerufen.

int x = p.execute(1);

x 1, nicht 2.

Generics geschieht in der Kompilierung. Es ist am besten, wenn Sie der gleiche Code wollen, um verschiedene Arten anzuwenden. Es ist nicht dynamisch, so dass es nicht hilft Ihnen zwischen Methoden wechseln je nach Eingangstypen.

Eine Überlastung der Lösung wie in David B Antwort funktioniert, aber geschieht auch während der Kompilierung.

Der Code in Ihrem Update macht das Gleiche. Es wirft (nach sorgfältiger Prüfung der Typen) und verwendet dann eine Überlastung der Methode zu lösen.

Ich glaube, dass Sie Methoden wechseln, basierend auf der Laufzeit eingegeben werden sollen.

Sie könnten ein dynamischeres Verhalten, wenn man Reflexion verwendet wird.

        public object execute(object obj) 
        {
            MethodInfo m = typeof(Parser).GetMethod(
                "action", 
                BindingFlags.Instance | BindingFlags.NonPublic, 
                null, 
                new Type[] { obj.GetType() }, 
                null);
            m.Invoke(this, new object[] { obj });
            return obj; 
        } 

Es ist vielleicht ein wenig zerbrechlich, aber es funktioniert im Beispiel.

IIRC können Sie die "where" Klausel verwenden, um dies zu ermöglichen

public T execute<T>(T obj) where : /* somthing */
{
}

ich immer bei Google habe, dass man sich selbst, damit ich es dabei belassen werden.

edit: einige Kommentare zu lesen. Ich würde raten, nicht typspezifischen Code aufrufen. setzen vielmehr, dass Code in einer virtuellen Funktion und rufen Sie das. Der Anruf Signatur könnte lange, aber das ist, was Auto abgeschlossen ist für.

Koodos joshua.ewer die man-Seite für die Suche nach

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