Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Создание универсальной процедуры синхронизции (маршалинга) из нескольких конкретных

1.8K
29 ноября 2008 года
NextTime
217 / / 19.12.2007
Имеется делегат:
 
Код:
Delegate Sub UpdateOb(ByVal Myobject As Object, ByVal value As String)

имеются синхронизирующие процедура, каждая из которых выполняет одну свою функцию:
Код:
Public Sub TextSet(ByVal Myobject As Object, ByVal value As String)
        If Myobject.InvokeRequired Then
            Myobject.Invoke(New UpdateOb(AddressOf TextSet), Myobject, value)
        Else
            Myobject.Text = value
        End If
    End Sub

    Public Sub TextAdd(ByVal Myobject As Object, ByVal value As String)
        If Myobject.InvokeRequired Then
            Myobject.Invoke(New UpdateOb(AddressOf TextAdd), Myobject, value)
        Else
            Myobject.Text &= value
        End If
    End Sub

    Public Sub EnableSet(ByVal Myobject As Object, ByVal value As String)
        If Myobject.InvokeRequired Then
            Myobject.Invoke(New UpdateOb(AddressOf EnableSet), Myobject, value)
        Else
            Myobject.Enabled = CBool(value)
        End If
    End Sub

    Public Sub IndexSet(ByVal Myobject As Object, ByVal value As String)
        If Myobject.InvokeRequired Then
            Myobject.Invoke(New UpdateOb(AddressOf IndexSet), Myobject, value)
        Else
            Myobject.SelectedIndex = value
        End If
    End Sub


Необходимо их превратить в одну универсалбну, которой передается объект, свойство и его значение, а потом процедура выполняет:
 
Код:
Объект.Свойство=Значение


Я пытался сделать так:
Делегат:
 
Код:
Delegate Sub UpdateOb(ByVal Myobject As Object, ByRef prop As String, ByVal value As String)

Процедура:
 
Код:
Public Sub Changing(ByVal Myobject As Object, ByRef prop As String, ByVal value As String)
        If Myobject.InvokeRequired Then
            Myobject.Invoke(New UpdateOb(AddressOf Changing), Myobject, prop, value)
        Else
            prop = value
        End If
    End Sub

и вызываю потом так:
 
Код:
Changing(TextBox1, Textbox1.Text, "Text")

prop специально передаю по ссылке (ByRef prop As String), чтобы изменения над prop отражались и на свойстве объекта. Но этого не происходит, свойство не изменяется. Как правильно сделать универсальную синхронизирующую процедуру, как передавать её свойство (ну или метод), которое я хочу изенить (или выполнить).
P.S. Я знаю, что задрал своими ламерскими вопросами (особенно hardcase'а), но в поиске это не напишешь, а сам разобраться не могу. Поверьте, себе моСк я рушу больше, чем вам:D
5
30 ноября 2008 года
hardcase
4.5K / / 09.08.2005
В духе
Код:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Reflection;

namespace WindowsApplication2 {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
            SetPropertySync(button1, "Text", "New button text");  // вот так использовать
        }

        private void SetPropertySync(object obj, string property_name, object new_value) {
            if (InvokeRequired) {
                Invoke((ThreadStart)delegate {
                    SetPropertySync(obj, property_name, new_value);
                });
            } else {
                SetProperty(obj, property_name, new_value);
            }
        }

        public static void SetProperty(object obj, string property_name, object new_value) {
            Type obj_type = obj.GetType();
            PropertyInfo property = obj_type.GetProperty(property_name, BindingFlags.Public | BindingFlags.Instance);
            property.SetValue(obj, new_value, null);
        }
    }
}
1.8K
30 ноября 2008 года
NextTime
217 / / 19.12.2007
Огромное спасибо, то что нужно. Позже попробую на практике... Без тебя бы я не смог справится, найти такие функции и методы. Только я запишу это одной процедурой, кратче будет... Поставил бы себе снова плюс, да форум не дает:) сейчас еще кому нибудь поставлю и тебе снова попробую
1.8K
30 ноября 2008 года
NextTime
217 / / 19.12.2007
И еще, может вы знаете, как быть с универсальной процедурой для выполнения методов, все тоже самое, только вместо изменения свойства, я в текстовом формате передаю метод, и он выполняется. Возможно ли это?
5
30 ноября 2008 года
hardcase
4.5K / / 09.08.2005
Цитата: NextTime
Возможно ли это?

Точно также, как и со свойствами.
Вместо GetProperty будет GetMethod, вместо PropertyInfo будет MethodInfo. Остальное нароете :)

Но вот все-таки мне кажется, лучше вам в чате использовать интерфейсы и сериализацию (xml-ню или двоичную).

1.8K
19 апреля 2009 года
NextTime
217 / / 19.12.2007
Кстати, давно думал как сделать такую же процедуру, только чтения значения свойства, приходилось обходить это глобальными переменными, но это некрасиво. Что посоветуете?
P.S. с методами так и до конца не разобрался....
5
19 апреля 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: NextTime
с методами так и до конца не разобрался....


Вот класс, в котором собрал методы для динамического обращения к свойствам (с синхронизацией с компонентой) и вызова методов:

Код:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Reflection;

namespace WindowsApplication1 {
   
    public static class DynamicExecutor {

        public static void SetProperty(Control control, object obj, string property_name, object new_value) {
            if (control.InvokeRequired) {
                control.Invoke((ThreadStart)delegate {
                    SetProperty(obj, property_name, new_value);
                });
            } else {
                SetProperty(obj, property_name, new_value);
            }
        }

        public static void SetProperty(object obj, string property_name, object new_value) {
            if(obj == null)
                throw new ArgumentNullException("obj");
            Type obj_type = obj.GetType();
            PropertyInfo property = obj_type.GetProperty(property_name, BindingFlags.Public | BindingFlags.Instance);
            if(property == null)
                throw new InvalidOperationException(string.Format("Property '{0}' not found in class '{1}.", property_name, obj_type));
            property.SetValue(obj, new_value, null);
        }

        public static void InvokeMethod(Control control, object obj, string method_name, params object[] args) {
            if (control.InvokeRequired) {
                control.Invoke((ThreadStart)delegate {
                    InvokeMethod(obj, method_name, args);
                });
            } else {
                InvokeMethod(obj, method_name, args);
            }
        }

        public static void InvokeMethod(object obj, string method_name, params object[] args) {
            if (obj == null)
                throw new ArgumentNullException("obj");
            Type obj_type = obj.GetType();
            Type[] arg_types = Array.ConvertAll<object, Type>(args, delegate(object arg) {
                return arg != null ? arg.GetType() : typeof(void);
            });
            MethodInfo method = obj_type.GetMethod(method_name, BindingFlags.Public | BindingFlags.Instance, null, arg_types, null);
            if (method == null)
                throw new InvalidOperationException(string.Format("Method '{0}' not found in class '{1}.", method_name, obj_type));
            method.Invoke(obj, args);
        }

    }
}
Вот так можно использовать с формой:
Код:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication1 {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
            DynamicExecutor.SetProperty(this, button1, "Text", "New button text");
        }

        private void button1_Click(object sender, EventArgs e) {
            DynamicExecutor.InvokeMethod(this, this, "Foo", "Hello!", 10, null);
        }

        public void Foo(string arg1, int arg2, object arg3) {
            MessageBox.Show(string.Format("arg1: {0}, arg2: {1}, arg3: {2}", arg1, arg2, arg3));
        }
    }
}
1.8K
19 апреля 2009 года
NextTime
217 / / 19.12.2007
Тут немножко не все. Мне нужно такую же процедуру, как у тебя SetProperty, только чисто для получения значения свойства, типа GetProperty. Я, конечно, давно догадался, что нужно использовать obj_type.GetValue, но как передать результат вызывающему? Я пробовал через глобальные переменные, но это плохо работает, через return тут тоже никак. Так как получить значение свойства из чужого потока.
1.8K
19 апреля 2009 года
NextTime
217 / / 19.12.2007
И еще... Я сейчас делаю программу, которая сама переименовывает фильмы, я вам рассказывал. Теперь я хочу переименовывать в отдельном потоке, посколько это очень долго. Но дело в том, что список имен файлов хранится в ListView1.CheckedItems, и в них есть SubItems... И мне этот список нужно получить в новом потоке, но как? Это чужой поток... Помогите...
5
19 апреля 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: NextTime
Тут немножко не все. Мне нужно такую же процедуру, как у тебя SetProperty, только чисто для получения значения свойства, типа GetProperty.


Дополнил класс семейством функций GetProperty:

Код:
public static class DynamicExecutor {

        public static void SetProperty(Control control, object obj, string property_name, object new_value) {
            if (control.InvokeRequired) {
                control.Invoke((ThreadStart)delegate {
                    SetProperty(obj, property_name, new_value);
                });
            } else {
                SetProperty(obj, property_name, new_value);
            }
        }

        public static void SetProperty(object obj, string property_name, object new_value) {
            if (obj == null)
                throw new ArgumentNullException("obj");
            Type obj_type = obj.GetType();
            PropertyInfo property = obj_type.GetProperty(property_name, BindingFlags.Public | BindingFlags.Instance);
            if (property == null)
                throw new InvalidOperationException(string.Format("Property '{0}' not found in class '{1}.", property_name, obj_type));
            property.SetValue(obj, new_value, null);
        }

        public static object GetProperty(Control control, object obj, string property_name) {
            if (control.InvokeRequired) {
                object result = null;
                control.Invoke((ThreadStart)delegate {
                    result = GetProperty(obj, property_name);
                });
                return result;
            } else {
                return GetProperty(obj, property_name);
            }
        }

        public static T GetProperty<T>(Control control, object obj, string property_name) {
            if (control.InvokeRequired) {
                T result = default(T);
                control.Invoke((ThreadStart)delegate {
                    result = GetProperty<T>(obj, property_name);
                });
                return result;
            } else {
                return GetProperty<T>(obj, property_name);
            }
        }

        public static object GetProperty(object obj, string property_name) {
            if (obj == null)
                throw new ArgumentNullException("obj");
            Type obj_type = obj.GetType();
            PropertyInfo property = obj_type.GetProperty(property_name, BindingFlags.Public | BindingFlags.Instance);
            if (property == null)
                throw new InvalidOperationException(string.Format("Property '{0}' not found in class '{1}.", property_name, obj_type));
            return property.GetValue(obj, null);
        }

        public static T GetProperty<T>(object obj, string property_name) {
            return (T)GetProperty(obj, property_name);
        }

        public static void InvokeMethod(Control control, object obj, string method_name, params object[] args) {
            if (control.InvokeRequired) {
                control.Invoke((ThreadStart)delegate {
                    InvokeMethod(obj, method_name, args);
                });
            } else {
                InvokeMethod(obj, method_name, args);
            }
        }

        public static void InvokeMethod(object obj, string method_name, params object[] args) {
            if (obj == null)
                throw new ArgumentNullException("obj");
            Type obj_type = obj.GetType();
            Type[] arg_types = Array.ConvertAll<object, Type>(args, delegate(object arg) {
                return arg != null ? arg.GetType() : typeof(void);
            });
            MethodInfo method = obj_type.GetMethod(method_name, BindingFlags.Public | BindingFlags.Instance, null, arg_types, null);
            if (method == null)
                throw new InvalidOperationException(string.Format("Method '{0}' not found in class '{1}.", method_name, obj_type));
            method.Invoke(obj, args);
        }

    }
5
19 апреля 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: NextTime
Теперь я хочу переименовывать в отдельном потоке, посколько это очень долго. Но дело в том, что список имен файлов хранится в ListView1.CheckedItems, и в них есть SubItems...

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

1.8K
19 апреля 2009 года
NextTime
217 / / 19.12.2007
я думал про это. Только я что-то запутался.... Какой объект считается созданным чужим потоком? Если я даже сформирую список заранее, то он ведь создастся главным потоком приложения, а использоваться будет рабочим.... Это ведь подходит под то, что один поток обращается к объекту, созданного другим потоком... Или я не прав?

P.S. Я сначала делал через Background Worker, но столкнулся точно также с передачей User-state объекта в Do_Work... возникало исключение, мол чужой поток.... я привык к обычным потокам....


Добавяю... Сделал так:
в классе формы объявил:
 
Код:
List<String> lst;

потом заполнил:
по нажатию кнопки:
 
Код:
lst = new List<String>();
foreach(ListViewItem item in lviewFilmIn.CheckedItems) lst.Add(item.Text);
thr = new Thread(search);
thr.IsBackground = true;
thr.Start();

и вроде работает...
Что-то немного не догоняю...Типы по-значению чужими в другом потоке не считаются, а по-ссылке считаются? или как?
5
19 апреля 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: NextTime
Типы по-значению чужими в другом потоке не считаются, а по-ссылке считаются? или как?

Поясню. Принадлежность тому или иному потоку - это уже фичи, навернутые в строго определенных иерархиях классов. Это техника "контекстно ограниченных объектов" (используется повсеместно в дотнете). В WinForms это все классы, наследованные от Control (кароче - все оконные компоненты), грубо говоря они своим контекстом считают поток, в котором были созданы.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог