it-swarm.com.de

Aufrufen einer statischen Methode für einen generischen Typparameter

Ich hatte gehofft, so etwas zu machen, aber es scheint in C # illegal zu sein:


public Collection MethodThatFetchesSomething<T>()
    where T : SomeBaseClass
{
    return T.StaticMethodOnSomeBaseClassThatReturnsCollection();
}

Ich erhalte die Fehlermeldung zur Kompilierungszeit: "'T' ist ein 'Typparameter', der im angegebenen Kontext nicht gültig ist."

Wie kann ich angesichts eines generischen Typparameters eine statische Methode für die generische Klasse aufrufen? Die statische Methode muss aufgrund der Einschränkung verfügbar sein.

97

In diesem Fall sollten Sie die statische Methode für den eingeschränkten Typ direkt aufrufen. C # (und die CLR) unterstützen keine virtuellen statischen Methoden. So:

T.StaticMethodOnSomeBaseClassThatReturnsCollection

... kann nicht anders sein als:

SomeBaseClass.StaticMethodOnSomeBaseClassThatReturnsCollection

Das Durchgehen des generischen Typparameters ist eine nicht benötigte Indirektion und wird daher nicht unterstützt.

53
JaredPar

Um auf eine vorherige Antwort näher einzugehen, denke ich, dass das Nachdenken dem näher kommt, was Sie hier wollen. Ich könnte 1001 Gründe nennen, warum Sie etwas tun sollten oder nicht, ich beantworte Ihre Frage einfach so, wie sie gestellt wurde. Ich denke, Sie sollten die GetMethod-Methode für den Typ des generischen Parameters aufrufen und von dort aus gehen. Zum Beispiel für eine Funktion:

public void doSomething<T>() where T : someParent
{
    List<T> items=(List<T>)typeof(T).GetMethod("fetchAll").Invoke(null,new object[]{});
    //do something with items
}

Dabei ist T eine Klasse mit der statischen Methode fetchAll ().

Ja, ich bin mir bewusst, dass dies furchtbar langsam ist und abstürzen kann, wenn someParent nicht alle untergeordneten Klassen zwingt, fetchAll zu implementieren, aber die gestellte Frage beantwortet.

25
Joshua Pech

Die einzige Möglichkeit, eine solche Methode aufzurufen, ist die Reflektion. Es scheint jedoch möglich zu sein, diese Funktionalität in eine Schnittstelle einzubinden und ein instanzbasiertes IoC/factory/etc-Muster zu verwenden.

7
Marc Gravell

Es hört sich so an, als würden Sie versuchen, mit Generika zu umgehen, dass C # keine "virtuellen statischen Methoden" enthält.

Das wird leider nicht funktionieren.

5
Brad Wilson

Hier poste ich ein Beispiel, das funktioniert, es ist eine Problemumgehung

public interface eInterface {
    void MethodOnSomeBaseClassThatReturnsCollection();
}

public T:SomeBaseClass, eInterface {

   public void MethodOnSomeBaseClassThatReturnsCollection() 
   { StaticMethodOnSomeBaseClassThatReturnsCollection() }

}

public Collection MethodThatFetchesSomething<T>() where T : SomeBaseClass, eInterface
{ 
   return ((eInterface)(new T()).StaticMethodOnSomeBaseClassThatReturnsCollection();
}
2
rodrijp

Ab jetzt kannst du nicht. Sie müssen dem Compiler mitteilen, dass T diese Methode hat, und derzeit gibt es keine Möglichkeit, dies zu tun. (Viele fordern Microsoft auf, das zu erweitern, was in einer allgemeinen Einschränkung angegeben werden kann. Möglicherweise wird dies in Zukunft möglich sein.).

2
James Curran

Ich wollte es nur rauswerfen, dass Delegierte diese Probleme manchmal lösen, je nach Kontext.

Wenn Sie die statische Methode als eine Art Factory- oder Initialisierungsmethode aufrufen müssen, können Sie einen Delegaten deklarieren und die statische Methode an die entsprechende generische Factory übergeben, oder was auch immer diese "generische Klasse mit dieser statischen Methode" benötigt.

Beispielsweise:

class Factory<TProduct> where TProduct : new()
{
    public delegate void ProductInitializationMethod(TProduct newProduct);


    private ProductInitializationMethod m_ProductInitializationMethod;


    public Factory(ProductInitializationMethod p_ProductInitializationMethod)
    {
        m_ProductInitializationMethod = p_ProductInitializationMethod;
    }

    public TProduct CreateProduct()
    {
        var prod = new TProduct();
        m_ProductInitializationMethod(prod);
        return prod;
    }
}

class ProductA
{
    public static void InitializeProduct(ProductA newProduct)
    {
        // .. Do something with a new ProductA
    }
}

class ProductB
{
    public static void InitializeProduct(ProductB newProduct)
    {
        // .. Do something with a new ProductA
    }
}

class GenericAndDelegateTest
{
    public static void Main()
    {
        var factoryA = new Factory<ProductA>(ProductA.InitializeProduct);
        var factoryB = new Factory<ProductB>(ProductB.InitializeProduct);

        ProductA prodA = factoryA.CreateProduct();
        ProductB prodB = factoryB.CreateProduct();
    }
}

Leider können Sie nicht erzwingen, dass die Klasse die richtige Methode hat, aber Sie können zumindest beim Kompilieren erzwingen, dass die resultierende Factory-Methode alles hat, was sie erwartet (d. H. Eine Initialisierungsmethode mit genau der richtigen Signatur). Dies ist besser als eine Laufzeitreflexionsausnahme.

Dieser Ansatz hat auch einige Vorteile, z. B. können Sie Init-Methoden wiederverwenden, Instanzmethoden usw.

2
Amir Abiri

Sie sollten in der Lage sein, dies unter Verwendung von Reflexion zu tun, wie es beschrieben ist hier

1
johnc