C # Reflection: возможно ли найти экземпляр объекта во время выполнения? - PullRequest
6 голосов
/ 16 сентября 2009

Мне интересно, возможно ли использовать отражение, чтобы найти объект во время выполнения? Это скорее эксперимент, чем практическое требование.

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

В качестве более конкретного примера, предположим, что у меня есть приложение WinForms, которое загружает DLL - как эта DLL может независимо находить ссылку на объект формы для взаимодействия с формой или вызывать открытый метод?

Возможно ли это вообще?

Ответы [ 7 ]

7 голосов
/ 16 сентября 2009

Нет, в основном.

У вас может быть какая-то ужасная глобальная карта от типа к "экземпляру типа, который мне интересен", но в противном случае нет.

По сути, приложение WinForms должно как-то передавать ссылку на форму в DLL.

1 голос
/ 16 сентября 2009

Нет, это невозможно, так как ссылки реализованы в частном порядке Microsoft, они не являются указателями по сравнению с C / C ++, в старых C / C ++ вы могли сканировать вашу память, но в .NET таких инструментов нет.

0 голосов
/ 22 ноября 2013

Джон Скит прав, что это невозможно для любого произвольного типа.

Для вашего конкретного примера это возможно. И вам не нужно p / invoke EnumWindows или использовать Form.FromHandle()

Form f = Application.OpenForms.Where(x => x.GetType().Name == "FormIWant").FirstOrDefault();
0 голосов
/ 16 сентября 2009

Если вы просто экспериментируете и пытаетесь найти основную форму из вашей DLL, вы можете сделать:

//get the current process
System.Diagnostics.Process p = System.Diagnostics.Process.GetCurrentProcess();

//get its main windows handle (only works, if the form is already created)
IntPtr hWnd = p.MainWindowHandle;

//locate the form by its native handle
System.Windows.Forms.Form f = System.Windows.Forms.Form.FromHandle(hWnd) as System.Windows.Forms.Form;

Только что проверил это для зависимых сборок, а не для динамически загружаемых. Но стоит попробовать.

На общую проблему определения местоположения конкретного экземпляра уже был дан ответ.

0 голосов
/ 16 сентября 2009

Как уже отвечали другие, нет, в общем случае это невозможно.

Но для более конкретного сценария вы можете получить список всех Windows из Win API, а затем проверить каждую из них на предмет свойств, которые вы пытаетесь найти.

public static class Helper
{
    public static IntPtr[] GetToplevelWindows()
    {
        List<IntPtr> windowList = new List<IntPtr>();
        GCHandle handle = GCHandle.Alloc(windowList);
        try
        {
            Helper.EnumWindows(Helper.EnumWindowsCallback, (IntPtr)handle);
        }
        finally
        {
            handle.Free();
        }

        return windowList.ToArray();
    }

    private delegate bool EnumWindowsCallBackDelegate(IntPtr hwnd, IntPtr lParam);

    [DllImport("user32.Dll")]
    private static extern int EnumWindows(EnumWindowsCallBackDelegate callback, IntPtr lParam);

    private static bool EnumWindowsCallback(IntPtr hwnd, IntPtr lParam)
    {
        ((List<IntPtr>)((GCHandle)lParam).Target).Add(hwnd);
        return true;
    }
}
0 голосов
/ 16 сентября 2009

Вы можете создать плагин для вашего приложения. Вот пример:

public interface IPlugin
{
void Load(Form mainForm); //Or you can have an interface for you main form that allows your plugin to work with your form.
}

тогда вы можете найти свои плагины при загрузке сборки во время выполнения.

foreach(var type in assembly.GetTypes())
{
if(typeof(IPlugin).IsAssignableFrom(type))
var plugin=(IPlugin)Activator.CreateInstance(type);
plugin.Load(_mainForm);
}

Обновление: Кстати, насколько я знаю, ответ на ваш вопрос - нет

0 голосов
/ 16 сентября 2009

Я не понял вашего вопроса. Когда вы ссылаетесь на объект, вы имеете в виду, что вы ищете экземпляр объекта, или вы имеете в виду поиск типа объекта?

Если вы ищете экземпляр, тогда ответ - нет. Если вы ищете тип по имени во время выполнения, тогда ответ - да.

Следующая строка позволит вам получить все загруженные сборки в AppDomain: AppDomain.CurrentDomain.GetAssemblies ();

Метод экземпляра Assembly.GetTypes() предоставит вам все типы в сборке.

Редактировать: забыл, что знал название типа. Вы также можете использовать Assembly.GetType(string name).

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