Получить имена методов интерфейса, строго типизированных
У меня есть интерфейс, как этот пример:
Interface IRequest{
List<profile> GetProfiles();
void SetProfile (Profile p);
}
Теперь в некоторых компонентах журналирования у меня нет доступа к объекту, реализующему интерфейс, но я хочу использовать имена методов в интерфейсе. я, конечно, могу напечатать их в виде строки (скопировать имя метода в строку), но я хочу использовать их строго типизированными, чтобы не синхронизировать имена методов и строки.
В псевдокоде я бы сделал это:
string s= IRequest.GetProfiles.ToString()
Это возможно?
РЕДАКТИРОВАТЬ:
Может быть, я должен назвать это: использовать интерфейс, как это строка Enum s= IRequest.GetProfiles.ToString()
5 ответов
Вы можете достичь этого двумя способами:
//If you CAN access the instance
var instance = new YourClass(); //instance of class implementing the interface
var interfaces = instance.GetType().GetInterfaces();
//Otherwise get the type of the class
var classType = typeof(YourClass); //Get Type of the class implementing the interface
var interfaces = classType.GetInterfaces()
А потом:
foreach(Type iface in interfaces)
{
var methods = iface.GetMethods();
foreach(MethodInfo method in methods)
{
var methodName = method.Name;
}
}
Иногда вы не знаете имя класса заранее, тогда вы можете использовать:
var interfaceType = typeof(InterfaceName);
var methods = interfaceType.GetMethods();
а потом:
List<String> methodNames = new List<String>();
foreach(var method in methods)
{
methodNames.Add(method.Name);
}
Обязательно проверьте, не является ли метод нулевым и содержит ли он хотя бы один элемент.
Это лучшее, чего я достиг, HTH:
using System;
using System.Collections.Generic;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace DotNetSandbox
{
// Subject interface to get names from
interface IRequest
{
List<object> GetProfiles();
void SetProfile(object p);
}
// Use case / Example:
[TestClass]
public class InterfaceNamesTests
{
[TestMethod]
public void InterfaceNamesTest()
{
// Option 1 - Not strongly typed
string name = typeof(IRequest).GetMethod("GetProfiles").Name;
Console.WriteLine(name); // OUTPUT: GetProfiles
// Option 2 - Strongly typed!!
var @interface = InterfaceNames<IRequest>.Create();
Func<List<object>> func = @interface.GetProfiles;
var name1 = func.Method.Name;
Console.WriteLine(name1); // OUTPUT: GetProfiles
Action<object> action = @interface.SetProfile;
var name2 = action.Method.Name;
Console.WriteLine(name2); // OUTPUT: SetProfile
// Other options results with complex/unclear code.
}
}
// Helper class
public class InterfaceNames<T> : RealProxy
{
private InterfaceNames() : base(typeof(T)) { }
public static T Create()
{
return (T)new InterfaceNames<T>().GetTransparentProxy();
}
public override IMessage Invoke(IMessage msg)
{
return null;
}
}
}
Ваш вопрос немного сложен для понимания. Я думаю, что вы хотите записать имя экземпляра класса или метода...
Если вы хотите строгую типизацию, я думаю, вам нужно использовать рефлексию. Конечно, вы можете добавить строковое имя к каждому классу, который может быть зарегистрирован, но это хрупкий код, и кто-то позже возненавидит вас за это. Вы видите этот стиль на языках, которые не всегда поддерживают рефлексию, но я бы рекомендовал против этого на таких языках, как C#.
Итак, к решению: Ваш метод регистрации вызывается изнутри экземпляра? Если это так, мы можем использовать отражение, чтобы получить имя вызывающего метода и много другой информации.
Если да, то что-то вроде этого может работать для вас:
class MyRequest: IRequest {
// other interface implementation details omitted
public void SetProfiles(Profile p) {
if(HasUglyPicture(p)) {
MyLogger.LogError(String.Format(
"User {0} update attempted with ugly picture", p.UserName)
throw new Exception("Profile update failed due to ugly picture!");
}
}
class MyLogger : ILogger {
// other logger details omitted
public void LogError(string errorMsg) {
// here's where you get the method name
// http://www.csharp-examples.net/reflection-calling-method-name/
StackTrace stackTrace = new StackTrace();
MyLogOutputStream.Write(stackTrace.GetFrame(1).GetMethod().Name);
MyLogOutputStream.WriteLine(errorMsg);
}
}
Этот вопрос переполнения стека может помочь: Как я могу получить вызывающие методы в C#
На этом сайте есть фрагмент кода, на котором основаны две важные строки: http://www.csharp-examples.net/reflection-calling-method-name/