5 Stimmen

Überladen von generischen Typ-Parametern nicht erlaubt?

Zum Teil aus Neugierde, zum Teil, weil ich es gerade benutzen wollte. Wenn Sie die folgenden Definitionen haben, wird dies vom Compiler nicht zugelassen, weil er sagt, dass das Mitglied bereits definiert ist. Was ist der Grund dafür, dass exklusive Überladungen von Parametern eines generischen Typs nicht erlaubt sind?

void Get<T>() where T: struct {}
void Get<T>() where T: class {}

Meines Erachtens gibt es hier kein inhärentes Problem. Man könnte argumentieren, dass es nicht immer klar ist, welche der Compiler in Fällen, in denen sich die Definitionen überschneiden, wählen sollte (aber eine gängige Lösung scheint zu sein, die spezifischste Übereinstimmung zuerst zu wählen).

Kann mir jemand helfen zu verstehen oder auf eine Quelle verweisen, aus welchen Gründen dies nicht erlaubt ist?

9voto

thecoop Punkte 43958

Eric Lippert hat diese Frage bereits in einem Blogbeitrag über generische Beschränkungen und Methodensignaturen beantwortet: http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx

Einschränkungen für generische Typen sind nicht Teil der Methodensignaturen in der CLR, daher können Sie nicht zwei Methoden haben, die sich nur durch Einschränkungen für generische Typen unterscheiden. Ohne CLR-Unterstützung wäre es ziemlich schwierig, C# zu bekommen, um diese in einer sinnvollen Weise zu unterstützen, die mit anderen .NET-Sprachen kompatibel ist.

1voto

supercat Punkte 72939

En struct Beschränkung auf Nullable<T> ist IMHO wirklich unglücklich. Etwas wie ein Nullable<String> o un Nullable<Nullable<Nullable<int>>> mag verschwenderisch sein, aber was soll's? Verpacken Sie das Erstere als seinen Inhalt; entpacken Sie es als seinen Inhalt und setzen Sie die HasValue wenn der Inhalt nicht null ist. Box die erste als eine int wenn alle Nullables sich melden HasValue und setzen Sie beim Auspacken HasValue aller verschachtelten Elemente, wenn der Inhalt nicht null ist.

Andernfalls würde ich vorschlagen, dass Sie eine statische generische Klasse mit Typparameter erstellen T die eine Delegateneigenschaft enthält, die eine T als Parameter. Die Eigenschaft sollte den Inhalt eines privaten Feldes zurückgeben, das initialisiert werden sollte, um auf eine Methode zu verweisen, die den Typ von T und setzen Sie den Delegaten entweder auf den struct o class Version, je nach Bedarf.

Hier ist ein Beispiel dafür, wovon ich spreche. In diesem Beispiel werden verschiedene Schnittstellenbeschränkungen anstelle von Struktur-/Klassenbeschränkungen verwendet, aber die gleichen Prinzipien können genauso effektiv eingesetzt werden.

        static class \_FooDispatcher<T>
        {
            public static Action<T> Foo = setupFoo;

            static void doFooWithIGoodFoo<TT>(TT param) where TT : IGoodFoo
            {
                Console.WriteLine("Dispatching as IGoodFoo with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference");
                param.Foo();
            }
            static void doFooWithIOkayFoo<TT>(TT param) where TT : IOkayFoo
            {
                Console.WriteLine("Dispatching as IOkayFoo with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference");
                param.Foo();
            }
            static void doFooSomehow<TT>(TT param)
            {
                Console.WriteLine("Nothing exciting with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference");
            }
            static void setupFoo(T param)
            {
                System.Reflection.MethodInfo mi;
                if (typeof(IGoodFoo).IsAssignableFrom(typeof(T)))
                    mi = typeof(\_FooDispatcher<T>).GetMethod("doFooWithIGoodFoo", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
                else if (typeof(IOkayFoo).IsAssignableFrom(typeof(T)))
                    mi = typeof(\_FooDispatcher<T>).GetMethod("doFooWithIOkayFoo", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
                else
                    mi = typeof(\_FooDispatcher<T>).GetMethod("doFooSomehow", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
                Foo = (Action<T>)(@Delegate.CreateDelegate(typeof(Action<T>), mi.MakeGenericMethod(typeof(T))));
                Foo(param);
            }
        }

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