Потокобезопасный метод расширения C # - PullRequest
3 голосов
/ 06 апреля 2010

Я, может быть, ваааааааа, или действительно близко. В любом случае, я в настоящее время SOL. :)

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

У меня есть класс, определенный примерно так:

public class ClassToUpdate : UIObservableItem
{
    private readonly Dispatcher mDispatcher = Dispatcher.CurrentDispatcher;
    private Boolean mPropertyToUpdate = false;

    public ClassToUpdate() : base()
    {
    }

    public Dispatcher Dispatcher
    {
        get { return mDispatcher; }
    }

    public Boolean PropertyToUpdate
    {
        get { return mPropertyToUpdate; }
        set { SetValue("PropertyToUpdate", ref mPropertyToUpdate, value; }
    }
}

У меня есть класс метода расширения, определенный примерно так:

static class ExtensionMethods
{
    public static IEnumerable<T> SetMyProperty<T>(this IEnumerable<T> sourceList,
                                                  Boolean newValue)
    {
       ClassToUpdate firstClass = sourceList.FirstOrDefault() as ClassToUpdate;

       if (firstClass.Dispatcher.Thread.ManagedThreadId != 
           System.Threading.Thread.CurrentThread.ManagedThreadId)
        {
            // WHAT GOES HERE?
        }
        else
        {
            foreach (var classToUpdate in sourceList)
            {
               (classToUpdate as ClassToUpdate ).PropertyToUpdate = newValue;
               yield return classToUpdate;
            }
        }
    }
}

Очевидно, я ищу "ЧТО ЗДЕСЬ" в методе расширения.

Спасибо, WTS

Ответы [ 2 ]

1 голос
/ 06 апреля 2010

// ЧТО ЗДЕСЬ?

mDispatcher.Invoke(new Action(() => sourceList.SetMyProperty(newValue)));

В качестве примечания: если вам нужно проверить, имеет ли текущий поток доступ к пользовательскому интерфейсу, вам не нужно сравнивать идентификаторы потоков. Вам просто нужно вызвать метод CheckAccess:

if (firstClass.Dispatcher.CheckAccess())
{
    ...
}

По какой-то причине этот метод скрыт в Intellisense ... понятия не имею, почему


UPDATE

ОК, мой ответ был не совсем точным ... вам все равно нужно yield return каждый элемент коллекции, а Invoke этого не делает. Вот еще одна версия вашего метода:

public static IEnumerable<T> SetMyProperty<T>(this IEnumerable<T> sourceList, bool newValue)
    where T : ClassToUpdate
{
    Action<T> setProperty = t => t.PropertyToUpdate = newValue;

    foreach(var t in sourceList)
    {
        if (t.Dispatcher.CheckAccess())
        {
            action(t);
        }
        else
        {
            t.Dispatcher.Invoke(action, new object[] { t });
        }
    }
}

Обратите внимание, что я добавил консистент к параметру универсального типа и удалил приведение (как вы это делали, генерики не принесли никакой пользы)

0 голосов
/ 07 апреля 2010

Просто для того, чтобы убрать пару небольших опечаток (и, надеюсь, не добавлять свои) в приведенном выше примере, вот окончательное решение для примера.

public static IEnumerable<T> SetMyProperty<T>(this IEnumerable<T> sourceList, 
    bool newValue) where T : ClassToUpdate
{
    Action<T> setProperty = t => t.PropertyToUpdate = newValue;

    foreach(var t in sourceList)
    {
        if (t.Dispatcher.CheckAccess())
        {
            setProperty(t);
        }
        else
        {
            t.Dispatcher.Invoke(setProperty, new object[] { t });
        }

        yield return t;
    }
}
...