Как поразмышлять над реализацией интерфейса C # из стека вызовов? - PullRequest
5 голосов
/ 01 октября 2010

Можно ли поразмышлять над явной реализацией интерфейса из стека вызовов?Я хочу использовать эту информацию для поиска атрибута на самом интерфейсе.

Учитывая этот код:

interface IFoo
{
    void Test();    
}

class Foo : IFoo
{
    void IFoo.Test() { Program.Trace(); }
}

class Program
{
    static void Main(string[] args)
    {
        IFoo f = new Foo();
        f.Test();
    }

    public static void Trace()
    {
        var method = new StackTrace(1, false).GetFrame(0).GetMethod();
        // method.???
    }
}

В частности, в Trace () я хотел бы иметь возможность получитьна typeof(IFoo) с method.

В окне просмотра, если я смотрю на method.ToString(), это дает мне Void InterfaceReflection.IFoo.Test() (InterfaceReflection - это название моей сборки).

Какя могу добраться до typeof(IFoo) оттуда?Должен ли я использовать поиск типа на основе имени из самой сборки, или Type IFoo?

ОБНОВЛЕНИЕ:

Вот окончательное решение, благодаря Kyte

public static void Trace()
{
    var method = new StackTrace(1, false).GetFrame(0).GetMethod();
    var parts = method.Name.Split('.');
    var iname = parts[parts.Length - 2];
    var itype = method.DeclaringType.GetInterface(iname);
}

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

Спасибо всем за помощь.

Ответы [ 4 ]

3 голосов
/ 01 октября 2010

Тестируя с VS2010, я нашел DeclaringType, который получает тип объекта, содержащий метод, откуда вы можете получить интерфейсы как объекты Type.

(я назвал проект TestConsole)

2 голосов
/ 01 октября 2010

method будет System.Reflection.RuntimeMethodInfo, который является производным от System.Reflect.MethodBase.Например, вы можете вызвать Invoke() (хотя, если вы сделали это в тот момент, когда получили его, то это приведет к бесконечной рекурсии, которая в конечном итоге умрет, переполнив стек).

Вызов ToString() возвращает полностью определенное имя.Вы называли проект InterfaceReflection?

Не уверен, что еще вы хотите.

Редактировать: Хорошо, теперь я делаю.Чтобы найти декларирующий тип, посмотрите на свойство DeclaringType, он вернет класс, в котором был объявлен метод (который может быть классом, в котором он был вызван, или базовый класс):это возвращает объект Type для Foo.

Теперь для хитрого бита, потому что вы заботитесь об интерфейсе, на котором он был объявлен.Однако может быть несколько интерфейсов, которые определяют метод с точно такой же сигнатурой, что означает простой вопрос: «Если это произошло из интерфейса, что это был за интерфейс?»не всегда есть один ответ.

Возможно, есть более удобный способ сделать это, но все, что я могу придумать, это вызвать GetInterfaces() для Type объекта, который вы получили от DeclaringType, изатем ищем того, чье имя совпадает с подписью метода.

0 голосов
/ 01 октября 2010

Я думаю, что .NET добавляет полное имя в начало свойства MethodInfo.Name, чтобы у него было уникальное имя для каждого метода.Представьте себе:

interface IFoo
{
    void Test();
}
interface IFoo2
{
    void Test();
}

class Foo : IFoo, IFoo2
{
    void IFoo.Test() { Trace(); }
    void IFoo2.Test() { Trace(); }
}

В этом случае typeof(Foo).GetMethods() вернет оба метода Test(), но их имена будут конфликтовать, поэтому я предполагаю, что они добавили имя интерфейса, чтобы сделать их уникальными?

MethodInfo.DeclaringType возвращает тип, содержащий реализацию.Так что если IFoo на самом деле был неким базовым типом, а не интерфейсом, и там было объявление базового метода, то .DeclaringType вернул бы тип базового класса.

Интересно, что я не могу найтифактическое имя интерфейса в любом месте в MethodInfo, так что, я думаю, вам придется искать его по имени, что-то вроде:

    public static void Trace()
    {
        var method = new System.Diagnostics.StackTrace(1, false).GetFrame(0).GetMethod();
        var fromType = method.DeclaringType;
        if (method.Name.Contains("."))
        {
            var iname = method.Name.Substring(0, method.Name.LastIndexOf('.'));
            fromType = Type.GetType(iname); // fromType is now IFoo.
        }
    }
0 голосов
/ 01 октября 2010

Я не хочу предполагать слишком много, но в этом случае, похоже, что вы можете вызвать некоторую путаницу, потому что Foo и Program взаимозависимы. Как правило, я думаю, что Program будет «владеть» Foo (который не зависит от Program) таким образом, чтобы он отвечал за настройку делегата, чтобы можно было избежать отражения ... как вы его настраиваете, Foo владеет "(на самом деле, я полагаю, что это зависит от, возможно, более точной) программы в некотором смысле (потому что она жестко обращается к своему Program.Trace ()), и программа" владеет "Foo таким образом (потому что она управляет экземпляром). 1001 *

Я не знаю, сработает ли это в вашем конкретном сценарии, но похоже, что операция типа события может иметь больше смысла и более просто обрабатывать связь.

ETA: Пример кода:

public interface IFoo
{
    event EventHandler Testing;
    void Test();
}
public class Foo : IFoo
{
    public event EventHandler Testing;
    protected void OnTesting(EventArgs e)
    {
        if (Testing != null)
            Testing(this, e);
    }
    public void Test()
    {
        OnTesting(EventArgs.Empty);
    }
}

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        IFoo f = new Foo();
        f.Testing += new EventHandler(f_Testing);
        f.Test();
    }

    static void f_Testing(object sender, EventArgs e)
    {
        IFoo foo = sender as IFoo;
        if (foo != null)
        { 
            //...
        }
    }
}

Возможно, я неправильно понял ваш вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...