puede - Método de interfaz C#ambigüedad
no se puede crear una instancia de la clase o interfaz abstracta c# (9)
Considere el siguiente ejemplo:
interface IBase1
{
int Percentage { get; set; }
}
interface IBase2
{
int Percentage { get; set; }
}
interface IAllYourBase : IBase1, IBase2
{
}
class AllYourBase : IAllYourBase
{
int percentage;
int Percentage {
get { return percentage; }
set { percentage = value; }
}
}
void Foo()
{
IAllYourBase iayb = new AllYourBase();
int percentage = iayb.Percentage; // Fails to compile. Ambiguity between ''Percentage'' property.
}
En el ejemplo anterior, hay ambigüedad entre qué propiedad Percentage
llamar. Suponiendo que las interfaces IBase1
e IBase2
no se puedan cambiar, ¿cómo resolvería esta ambigüedad de la manera más limpia y preferida?
Actualizar
Basándome en las respuestas que recibí por usar una implementación de interfaz explícita, quiero mencionar que aunque esto resuelve el problema, no lo resuelve de manera ideal para mí porque uso mi objeto AllYourBase
como IAllYourBase
mayor parte del tiempo, nunca como una IBase1
o IBase2
. Esto se debe principalmente a que IAllYourBase
también tiene métodos de interfaz (no pude detallar aquellos en mi fragmento de código anterior porque pensé que eran irrelevantes) implementados por AllYourBase
y quiero acceder a ellos también. Repartir de un lado a otro todo el tiempo será muy tedioso y resultará en un código desordenado.
IAllYourBase
una solución que implicaba definir la propiedad de Percentage
en IAllYourBase
y no usar la implementación de la interfaz explícita, que parecía eliminar el error del compilador al menos:
class IAllYourBase : IBase1, IBase2
{
int Percentage { get; set; }
}
¿Es esta una solución válida?
Aunque ya has aceptado la respuesta. Yo diría que la implementación explícita requiere demasiado trabajo redundante (¡En su caso, implementar la misma propiedad dos veces!)
¿Qué tal una mayor segregación de la interfaz (Principio de Segregación de Inteface)?
internal interface IPercentage
{
int Percentage { get; set; }
}
internal interface IBase1 : IPercentage
{
}
internal interface IBase2 : IPercentage
{
}
internal interface IAllYourBase : IBase1, IBase2
{
}
internal class AllYourBase : IAllYourBase
{
private int percentage;
public int Percentage
{
get { return percentage; }
set { percentage = value; }
}
void Foo()
{
IAllYourBase iayb = new AllYourBase();
int percentage = iayb.Percentage; // Compiles now!!!
}
}
Implementar explícitamente y acceder a él:
interface IAllYourBase : IBase1, IBase2 { }
public class AllYourBase : IAllYourBase
{
int IBase1.Percentage { get{ return 12; } }
int IBase2.Percentage { get{ return 34; } }
}
IAllYourBase base = new AllYourBase();
int percentageBase1 = (base as IBase1).Percentage;
int percentageBase2 = (base as IBase2).Percentage;
Implementar explícitamente:
public class AllYourBase : IBase1, IBase2
{
int IBase1.Percentage { get{ return 12; } }
int IBase2.Percentage { get{ return 34; } }
}
Si hace esto, por supuesto puede tratar sus propiedades no ambiguas como si fueran normales.
IAllYourBase ab = new AllYourBase();
ab.SomeValue = 1234;
Sin embargo, si desea acceder al porcentaje de prop, esto no funcionará (suponga que sí, ¿qué valor se esperaría a cambio?)
int percent = ab.Percentage; // Will not work.
necesita especificar qué porcentaje devolver. Y esto se hace lanzando a la interfaz correcta:
int b1Percent = ((IBase1)ab).Percentage;
Como dices, puedes redefinir las propiedades en la interfaz:
interface IAllYourBase : IBase1, IBase2
{
int B1Percentage{ get; }
int B2Percentage{ get; }
}
class AllYourBase : IAllYourBase
{
public int B1Percentage{ get{ return 12; } }
public int B2Percentage{ get{ return 34; } }
IBase1.Percentage { get { return B1Percentage; } }
IBase2.Percentage { get { return B2Percentage; } }
}
Ahora has resuelto la ambigüedad por nombres distintos.
Implementar las interfaces explícitamente.
Una implementación de miembro de interfaz explícita es un método, propiedad, evento o declaración de indexador que hace referencia a un nombre de miembro de interfaz completamente calificado
Vea esta página de MSDN para un tutorial detallado.
interface AllYourBase : IBase1, IBase2
{
int IBase1.Percentage { get; set; }
int IBase2.Percentage { get; set; }
}
Puede definir la propiedad en la interfaz IAllYourBase
.
Algo como esto :
interface IAllYourBase : IBase1, IBase2
{
new int Percentage { get; set; }
}
Esto resolverá los problemas con la ambigüedad entre las propiedades. Y puedes mantener la estructura de las interfaces.
Si bien la implementación explícita que los chicos han mencionado es obviamente correcta, considere seguir los guiones solo por razones de cordura (o hágalo solo para una persona que lea su código en el futuro):
Si estos porcentajes tienen diferentes significados según la interfaz, ¿por qué no darles nombres significativos?
interface IBase1
{
int PercentageBase1 { get; set; }
}
interface IBase2
{
int PercentageBase2 { get; set; }
}
Y, por otro lado, si tienen el mismo significado, ¿por qué no tener solo un Porcentaje en una de las interfaces y derivar uno de otro?
interface IBase1
{
int Percentage { get; set; }
}
interface IBase2 : IBase1
{
}
Sin embargo, si la última operación no es posible por el motivo que sea, considere crear una interfaz base que contenga esa propiedad para ambos:
interface IBase0
{
int Percentage { get; set; }
}
interface IBase1 : IBase0
{
}
interface IBase2 : IBase0
{
}
Si en realidad no necesita devolver valores diferentes para la propiedad Percentage
, puede eliminar el error del compilador "derivando" de cada interfaz por separado, en lugar de la interfaz "maestra":
public class AllYourBase : IBase1, IBase2
{
// No need to explicitly implement if the value can be the same
public double Percentage { get { return 12d; } }
}
Por supuesto, si necesita valores separados, tendrá que implementar explícitamente las interfaces y acceder a la propiedad a través de una referencia escrita correctamente:
public class AllYourBase : IBase1, IBase2
{
// No need to explicitly implement if the value can be the same
public double IBase1.Percentage { get { return 12d; } }
public double IBase2.Percentage { get { return 34d; } }
}
Y el código:
public void SomeMethod()
{
AllYourBase ayb = new AllYourBase();
IBase1 b1 = ayb
double p1 = b1.Percentage;
IBase2 b2 = ayb;
double p2 = b2.Percentage;
}
Una consideración importante al implementar las interfaces explícitamente es que AllYourBase
ya no tiene una propiedad de Percentage
. Solo se puede acceder cuando se accede al objeto a través de una referencia escrita como una de las interfaces:
public void SomeMethod()
{
AllYourBase ayb = new AllYourBase();
double d = ayb.Percentage; // This is not legal
}
ACTUALIZACIÓN : Mirando su edición, su solución está bien, asumiendo que no necesita un comportamiento diferente para IBase1
e IBase2
. Su solución oculta esas propiedades, por lo que solo serán accesibles al convertir el objeto en una de esas dos interfaces.
Suponiendo que desea que ambas propiedades accedan a la variable de porcentaje de miembro, puede lograr esto utilizando una implementación de interfaz explícita y extendiendo la interfaz IAllYouBase
interface IAllYourBase : IBase1, IBase2
{
new int Percentage { get; set; }
}
class AllYourBase : IAllYourBase
{
int percentage;
public int Percentage {
get { return percentage; }
set { percentage = value; }
}
int IBase1.Percentage {
get { return percentage; }
set { percentage = value; }
}
int IBase2.Percentage {
get { return percentage; }
set { percentage = value; }
}
}
No es bonito, pero te dará el comportamiento que creo que estás buscando.
void Foo()
{
IAllYourBase base = new AllYourBase();
int percentage = base.Percentage; // Fails to compile. Ambiguity between ''Percentage'' property.
}
En este ejemplo, usa la palabra clave base
para un nombre de objeto y eso puede estar causando el problema.