Получить имена методов интерфейса, строго типизированных

У меня есть интерфейс, как этот пример:

Interface IRequest{

  List<profile> GetProfiles();
  void SetProfile (Profile p);
}

Теперь в некоторых компонентах журналирования у меня нет доступа к объекту, реализующему интерфейс, но я хочу использовать имена методов в интерфейсе. я, конечно, могу напечатать их в виде строки (скопировать имя метода в строку), но я хочу использовать их строго типизированными, чтобы не синхронизировать имена методов и строки.

В псевдокоде я бы сделал это:

string s= IRequest.GetProfiles.ToString()

Это возможно?

РЕДАКТИРОВАТЬ:

Может быть, я должен назвать это: использовать интерфейс, как это строка Enum s= IRequest.GetProfiles.ToString()

5 ответов

Вы можете использовать это

nameof(Interface.Method)

это просто

Вы можете достичь этого двумя способами:

//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/

Другие вопросы по тегам