c# - puede - que es una interfaz en programacion
Cómo llamar a un método de interfaz implementado explícitamente en la clase base (6)
¿Es necesario explícitamente? ... ¿Se puede usar una clase o clase abstracta en lugar de una interfaz?
interface ISample {}
class A : ISample {}
class B : A {}
...
base.fun();
...
http://msdn.microsoft.com/en-us/library/hfw7t1ce(v=vs.71).aspx
No tengo idea de que no sea posible el método base de llamadas cuando se trata de la implementación de la interfaz.
Tengo una situación en la que dos clases (una derivada de la otra) implementan la misma interfaz explícitamente:
interface I
{
int M();
}
class A : I
{
int I.M() { return 1; }
}
class B : A, I
{
int I.M() { return 2; }
}
Desde la implementación de la clase derivada de IM()
, me gustaría llamar a la implementación de la clase base, pero no veo cómo hacerlo. Lo que intenté hasta ahora es esto (en la clase B):
int I.M() { return (base as I).M() + 2; }
// this gives a compile-time error
//error CS0175: Use of keyword ''base'' is not valid in this context
int I.M() { return ((this as A) as I).M() + 2; }
// this results in an endless loop, since it calls B''s implementation
¿Hay alguna forma de hacerlo sin tener que implementar otro método auxiliar (no explícito en la interfaz)?
Actualización :
Sé que es posible con un método "auxiliar" que puede ser llamado por la clase derivada, por ejemplo:
class A : I
{
int I.M() { return M2(); }
protected int M2 { return 1; }
}
También puedo cambiarlo para implementar la interfaz de forma no explícita. Pero me preguntaba si es posible sin ninguna de estas soluciones.
Aquí está mi versión de la solución agradable de Roland Pihlakas. Esta versión admite toda la cadena de herencia en lugar de la clase base inmediata. El método Invoke incluye parámetros adicionales y hay un tipo vooke Invoke para métodos sin función.
public class BaseClassExplicitInterfaceInvoker<T>
{
readonly Dictionary<string, MethodInfo> Cache = new Dictionary<string, MethodInfo>();
MethodInfo FindMethod(string MethodName)
{
if (Cache.TryGetValue(MethodName, out var Result)) return Result;
var BaseType = typeof(T);
while (Result == null)
{
if ((BaseType = BaseType.BaseType) == typeof(object)) break;
var Methods = BaseType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
Result = Methods.FirstOrDefault(X => X.IsFinal && X.IsPrivate && (X.Name == MethodName || X.Name.EndsWith("." + MethodName)));
}
if (Result != null) Cache.Add(MethodName, Result);
return Result;
}
public void Invoke(T Object, string MethodName, params object[] Parameters) => FindMethod(MethodName).Invoke(Object, Parameters);
public ReturnType Invoke<ReturnType>(T Object, string MethodName, params object[] Parameters) => (ReturnType)FindMethod(MethodName).Invoke(Object, Parameters);
}
No puede llamar al método de interfaz explícita en la clase base, aquí resolví este problema
Tengo dos interfaces -> Interface1 y Interface2
public interface Interface1
{
string method2();
}
public interface Interface2
{
string method22();
}
Método de la clase principal
class Program
{
static void Main(string[] args)
{
class1 cls = new class1();
string str = cls.method2();
}
}
y mi interfaz implementada clase
class class1 : Interface1, Interface2
{
#region Interface1 Members
public string method2()
{
return (this as Interface2).method22();
}
#endregion
#region Interface2 Members
string Interface2.method22()
{
return "2";
}
#endregion
}
Desafortunadamente, no es posible.
Ni siquiera con un método de ayuda. El método auxiliar tiene los mismos problemas que en su segundo intento: this
es de tipo B
, incluso en la clase base y llamará a la implementación de M
en B
:
interface I
{
int M();
}
class A : I
{
int I.M() { return 1; }
protected int CallM() { return (this as I).M(); }
}
class B : A, I
{
int I.M() { return CallM(); }
}
La única solución alternativa sería un método auxiliar en A
que se use en la implementación de M
de M
:
interface I
{
int M();
}
class A : I
{
int I.M() { return CallM(); }
protected int CallM() { return 1; }
}
class B : A, I
{
int I.M() { return CallM(); }
}
Pero necesitarías proporcionar un método como este también para B
si habrá una class C : B, I
...
Es posible utilizar la reflexión.
El código sigue. methodInfo
el almacenamiento en caché como una optimización básica, pero se puede optimizar aún más usando Delegate.CreateDelegate
en methodInfo
. Además, el conteo de parámetros y las verificaciones de tipos se pueden agregar usando methodInfo.GetParameters()
.
interface I
{
int M();
}
class A : I
{
int I.M() { return 1; }
}
class B : A, I
{
BaseClassExplicitInterfaceInvoker<B> invoker = new BaseClassExplicitInterfaceInvoker<B>();
int I.M() { return invoker.Invoke<int>(this, "M") + 2; }
}
public class BaseClassExplicitInterfaceInvoker<T>
{
private Dictionary<string, MethodInfo> cache = new Dictionary<string, MethodInfo>();
private Type baseType = typeof(T).BaseType;
private MethodInfo FindMethod(string methodName)
{
MethodInfo method = null;
if (!cache.TryGetValue(methodName, out method))
{
var methods = baseType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
foreach (var methodInfo in methods)
{
if (methodInfo.IsFinal && methodInfo.IsPrivate) //explicit interface implementation
{
if (methodInfo.Name == methodName || methodInfo.Name.EndsWith("." + methodName))
{
method = methodInfo;
break;
}
}
}
cache.Add(methodName, method);
}
return method;
}
public RT Invoke<RT>(T obj, string methodName)
{
MethodInfo method = FindMethod(methodName);
return (RT)method.Invoke(obj, null);
}
} //public static class BaseClassExplicitInterfaceInvoker<T>
Here está la fuente de mi inspiración.
using System;
namespace SampleTest
{
interface IInterface1
{
void Run();
}
interface IInterface2
{
void Run();
}
public class BaseClass : IInterface1, IInterface2
{
public void Interface1Run()
{
(this as IInterface1).Run();
}
public void Interface2Run()
{
(this as IInterface2).Run();
}
void IInterface2.Run()
{
Console.WriteLine("I am from interface 2");
}
void IInterface1.Run()
{
Console.WriteLine("I am from interface 1");
}
}
public class ChildClass : BaseClass
{
public void ChildClassMethod()
{
Interface1Run();
Interface2Run();
}
}
public class Program : ChildClass
{
static void Main(string[] args)
{
ChildClass childclass = new ChildClass();
childclass.ChildClassMethod();
}
}
}