Laden...

Compiler bevorzugt generische Methodenvariante --> Compilerfehler

Erstellt von winSharp93 vor 14 Jahren Letzter Beitrag vor 14 Jahren 955 Views
winSharp93 Themenstarter:in
5.742 Beiträge seit 2007
vor 14 Jahren
Compiler bevorzugt generische Methodenvariante --> Compilerfehler

Hallo zusammen,

um mir etwas Tipparbeit zu sparen habe ich folgende Erweiterungsklasse geschrieben:


public static class EqualsExtensions
{
    public static bool EqualsOneOf(this object first, params object[] others)
    {
        return others.Any(o => Object.Equals(first, o));
    }
    public static bool EqualsOneOf<T>(this T first, params T[] others)
        where T : IEquatable<T>
    {
        if (Object.ReferenceEquals(first, null))
            return others.Any(o => Object.ReferenceEquals(o, null));

        return others.Any(o => first.Equals(o));
    }
}

Nun verwende ich sie wie folgt:


bool b1 = "Hallo Welt".EqualsOneOf("Hallo Welt", "Hello World");
bool b2 = new Foo().EqualsOneOf(new Foo());
bool b3 = EqualsExtensions.EqualsOneOf(new Foo(), new Foo());

Wobei Foo so aussieht:


public sealed class Foo
{

}

Allerdings erhalte ich nun zwei Compilerfehldermeldungen für die letzten beiden Zeilen:

The type 'Foo' cannot be used as type parameter 'T' in the generic type or method 'EqualsExtensions.EqualsOneOf<T>(T, params T[])'. There is no implicit reference conversion from 'ConsoleApplication1.Foo' to 'IEquatable<Foo>'

Kommentiere ich nun allerdings die generische EqualsOneOf aus, kompiliert alles wunderbar.

Meine Frage nun:
Warum hält der Compiler an der generischen Variante fest und weicht nicht auf die nicht-generische aus?
Er scheint ja zu merken, dass Foo das Constraint auf IEquatable<T> nicht erfüllen kann.

Gibt es dafür irgendwo eine Erklärung in der MSDN?
Ich habe nämlich keine logische Erklärung dafür gefunden 🤔

Viele Grüße
winSharp93

Gelöschter Account
vor 14 Jahren

Hast du es schon mal nicht statisch probiert und geschaut ob das verhalten gleich bleibt. Einfach mal testweise.
.NET 3.5 ??

winSharp93 Themenstarter:in
5.742 Beiträge seit 2007
vor 14 Jahren

.NET 3.5 ??

Ja, C# 3.0 unter .NET 3.5 SP1.

Hast du es schon mal nicht statisch probiert und geschaut ob das verhalten gleich bleibt.

Keine Änderung.

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo winSharp93,

der Compiler wählt erst anhand der Parametertypen die Methodendefinition, die am besten passt. Und erst wenn er sich auf eine Methode festgelegt hat, prüft er die Contrains. Wenn du die Methode mit einem Objekt vom Typ Object aufgerufen würdest, würde er die erste Methodenimplementierung wählen, aber wenn das Objekt nicht vom Typ Object ist, dann passt halt die zweite Implementierung besser.

Es ist ja auch nicht möglich zwei Methoden zu definieren, die die gleichen Parametertypen haben und sich nur im Constrain unterscheiden.

Ich verstehe schon, was du erreichen willst, aber das geht wohl leider nicht.

herbivore

winSharp93 Themenstarter:in
5.742 Beiträge seit 2007
vor 14 Jahren

der Compiler wählt erst anhand der Parametertypen die Methodendefinition, die am besten passt. [...]

Tja - also sozusagen Bug und Feature zugleich. 😁

Dann werde ich wohl auch bei meinem bisherigen Workaround bleiben und nur die nichtgenerische zur Verfügung stellen - wenn auch mit dem verbundenen Boxing.

S
248 Beiträge seit 2008
vor 14 Jahren

Hallo,

etwas zu deiner Klasse selbst ...

public static class EqualsExtensions
{
	public static bool EqualsOneOf(this object first, params object[] others)
	{
		return others.Any(o => Object.Equals(first, o));
	}

	public static bool EqualsOneOf<T>(this IEquatable<T> first, params T[] others)
	{
		if (Object.ReferenceEquals(first, null))
			return others.Any(o => Object.ReferenceEquals(o, null));

		return others.Any(o => first.Equals(o));
	}
}

Wäre diese Implementierung nicht "korrekter"? Die Methode soll schauen ob "first" zu einem der folgenden Objekte equivalent ist. Dies bedeut aber streng genommen nicht, dass diese auch IEquatable<T> implementieren, sondern nur vom Typen T sein müssen.

Spooky

winSharp93 Themenstarter:in
5.742 Beiträge seit 2007
vor 14 Jahren

Wäre diese Implementierung nicht "korrekter"?

In meinem Fall haben eigentlich alle Objekte, die ich auf diese Weise vergleiche, denselben Typ (vornehmlich Strukturen).

Aber jedenfalls lässt sich das Problem so lösen - nehme ich 😁
Danke!