Получить ссылку на объект, который вызвал метод?

у меня есть DLL, которая включает в себя:

public abstract class Module
{
   internal int ID;

   public abstract void ModuleStart();

}

public void function1() {}
public void function2() {}
//etc...

и тогда у меня есть другая dll, которая ссылается на вышеуказанную dll и имеет:

class MyModule : Module
{
   public override void ModuleStart()
   {
      function1();

   }

}

то, что я хотел бы сделать, это иметь function1, известное значение идентификатора вызывающего модуля, без его передачи. Есть ли способ сделать это? В основном то, что я пытаюсь сделать, загружается основная DLL модуля, запускается метод, который загружается во вторую dll, использует отражение, чтобы убедиться, что у него есть дочерний модуль, назначает ему идентификатор и запускает ModuleStart. Mymodule может делать то, что ему нужно, вызывая функции из первой dll для доступа к внутренней защищенной памяти, но когда функции вызываются, они должны знать идентификатор модуля, который их вызвал. Возможно ли это? MyModule не имеет ни знания о своем ID, ни способности изменить его.

3 ответов


.NET 4.5 добавляет некоторые функции, чтобы сделать что-то подобное с CallerMemberNameAttribute. Вот пример из документов:

public void TraceMessage(string message,
        [CallerMemberName] string memberName = "",
        [CallerFilePath] string sourceFilePath = "",
        [CallerLineNumber] int sourceLineNumber = 0)
{
    Trace.WriteLine("message: " + message);
    Trace.WriteLine("member name: " + memberName);
    Trace.WriteLine("source file path: " + sourceFilePath);
    Trace.WriteLine("source line number: " + sourceLineNumber);
}

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

учитывая этот факт, короткий ответ заключается в том, что вы должны предоставить Module object в качестве параметра для методов, вызываемых в DLL. Метод, предложенный @p.s.w.g является одним из способов достижения этого, но имеет недостаток в потенциальном загрязнении пространства символов Module класса. Это можно решить, имея Module класс реализует защищенный или открытый член API, который предоставляет функции, которые вы хотите обеспечить:

public abstract class Module
{
    internal int ID;

    public class APIWrapper
    {
        Module module;

        public APIWrapper(Module module)
        {
            this.module = module;
        }

        public void method1() { apiimpl.method1(this.module); }
        public int method2() { return apiimpl.method2(this.module); }
    }

    public readonly APIWrapper API;

    public Module()
    {
        ID = generate_module_identity();
        API = new APIWrapper(this);
    }

    public abstract void ModuleStart();
}

internal static class apiimpl
{
    public static void method1(Module module) { ... }
    public static int method2(Module module) { ... }
}
другие разработчики могут использовать его таким образом:
class MyModule : Module
{
    public override void ModuleStart()
    {
        API.method1();
    }
}

это инкапсулирует методы, которые предоставляет ваша DLL, без введения слишком большого загрязнения пространства символов Module иерархия классов.

[тип мнения= " мое "значение= "YMMV"]

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

[/мнение]


если то, что вы действительно хотите, это просто получить ID во время выполнения, без передачи каких-либо аргументов в function1, вы можете использовать унаследованные методы:

public abstract class Module
{
    internal int ID;
    public abstract void ModuleStart();

    protected void function1()
    {
        System.Console.WriteLine ("function1 called from module {0}", this.ID);
    }
}

затем, из других ваших модулей, вызывая function1 выглядит так просто, как это:

class MyModule : Module
{
   public override void ModuleStart()
   {
      this.function1();    // the 'this.' is not required
   }
}

тем не менее, я получаю смысл от ваших комментариев, которые вы хотите сделать, чтобы эти функции были отделены от ваших Module класс, так как вы регулярно добавляете новые функции. Вы можете сделать почти то же самое, используя методы расширения сохранить внешний вид не проходить никакие параметры:

public abstract class Module
{
   internal int ID;
   public abstract void ModuleStart();
}

public static class ModuleExtensions
{
   public static void function1(this Module module)
   {
       innerFunction1(module.ID);
   }

   internal static void innerFunction1(int ID)
   {
        System.Console.WriteLine ("function1 called from module {0}", ID);
   }
}

затем, из других ваших модулей, вызывая function1 выглядит так просто, как это:

class MyModule : Module
{
   public override void ModuleStart()
   {
      this.function1();     // the 'this.' is required
   }
}