Comment faire pour lever l'ambiguïté entre les deux constructeurs lorsque les deux paramètres de type sont les mêmes?
Je vais commencer par ne pas répondre à votre question, puis terminer avec une réponse réelle qui vous permet de contourner ce problème.
Vous n'avez pas parce que vous ne devriez jamais vous vous retrouvez dans cette position en premier lieu. C'est une erreur de conception pour créer un type générique qui peut causer des signatures de membres d'être unifié dans cette manière. Ne jamais écrire une classe comme ça.
Si vous revenez en arrière et lire l'original C# 2.0, vous verrez que la conception originale était d'avoir le compilateur de détecter les types génériques dans lequel il a été en aucune façon possible pour ce genre de problème à se présenter, et de faire la déclaration de classe illégale. Ce qu'il a faites dans les spécifications publiées, même si cela était une erreur, l'équipe de conception réalisé que cette règle était trop strict en raison de scénarios tels que:
class C<T>
{
public C(T t) { ... }
public C(Stream s) { ... deserialize from the stream ... }
}
Il serait bizarre de dire que cette classe est illégal parce que vous pourriez dire C<Stream>
puis être incapable de lever l'ambiguïté entre les constructeurs. Au lieu de cela, une règle a été ajoutée à la résolution de surcharge qui dit que si il y a un choix entre (Stream)
et (T where Stream is substituted for T)
le premier gagne.
Ainsi, la règle que ce genre d'unification est illégal a été abandonné et il est désormais autorisé. Cependant c'est une très, très mauvaise idée de faire des types d'unifier, de cette manière. Le CLR qu'il gère mal dans certains cas, et il est source de confusion pour le compilateur et les développeurs. Par exemple, pourriez-vous deviner à la sortie de ce programme?
using System;
public interface I1<U> {
void M(U i);
void M(int i);
}
public interface I2<U> {
void M(int i);
void M(U i);
}
public class C3: I1<int>, I2<int> {
void I1<int>.M(int i) {
Console.WriteLine("c3 explicit I1 " + i);
}
void I2<int>.M(int i) {
Console.WriteLine("c3 explicit I2 " + i);
}
public void M(int i) {
Console.WriteLine("c3 class " + i);
}
}
public class Test {
public static void Main() {
C3 c3 = new C3();
I1<int> i1_c3 = c3;
I2<int> i2_c3 = c3;
i1_c3.M(101);
i2_c3.M(102);
}
}
Si vous compilez ce avec des messages d'avertissement est activée, vous verrez l'avertissement que j'ai ajouté en expliquant pourquoi c'est une très, très mauvaise idée.
Non, vraiment: Comment faire pour lever l'ambiguïté entre les deux constructeurs lorsque les deux paramètres de type sont les mêmes?
Comme ceci:
static Either<A, B> First<A, B>(A a) => new Either<A, B>(a);
static Either<A, B> Second<A, B>(B b) => new Either<A, B>(b);
...
var ess1 = First<string, string>("hello");
var ess2 = Second<string, string>("goodbye");
qui est la façon dont la classe doit avoir été conçu en premier lieu. L'auteur de l' Either
classe devrait avoir écrit
class Either<A, B>
{
private Either(A a) { ... }
private Either(B b) { ... }
public static Either<A, B> First(A a) => new Either<A, B>(a);
public static Either<A, B> Second(B b) => new Either<A, B>(b);
...
}
...
var ess = Either<string, string>.First("hello");