C# 线程安全扩展方法

发布于 2024-08-27 18:18:17 字数 1464 浏览 9 评论 0原文

我可能已经离开了,或者真的很接近了。不管怎样,我目前是 SOL。 :)

我希望能够使用扩展方法来设置类的属性,但该类可能(也可能不会)在非 UI 线程上更新,并且派生自强制更新在 UI 上的类线程(实现 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;
            }
        }
    }
}

显然,我正在扩展方法中寻找“这里有什么”。

谢谢, 工作时间

I may be waaaay off, or else really close. Either way, I'm currently SOL. :)

I want to be able to use an extension method to set properties on a class, but that class may (or may not) be updated on a non-UI thread, and derives from a class the enforces updates to be on the UI thread (which implements INotifyPropertyChanged, etc).

I have a class defined something like this:

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; }
    }
}

I have an extension method class defined something like this:

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;
            }
        }
    }
}

Obviously, I'm looking for the "WHAT GOES HERE" in the extension method.

Thanks,
wTs

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

玉环 2024-09-03 18:18:17

// 这里有什么?

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

附带说明一下,如果您需要检查当前线程是否有权访问 UI,则无需比较线程 ID。您只需要调用 CheckAccess 方法:

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

出于某种原因,此方法隐藏在 Intellisense 中...不知道为什么


更新

好吧,我的答案并不完全准确...您仍然需要 < code>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 });
        }
    }
}

请注意,我在泛型类型参数上添加了一个约束,并且删除了强制转换(按照您的方式,泛型没有带来任何好处)

// WHAT GOES HERE?

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

As a side note, if you need to check whether the current thread has access to the UI, you don't need to compare thread ids. You just need to call the CheckAccess method :

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

For some reason, this methods is hidden in Intellisense... no idea why


UPDATE

OK, my answer wasn't totally accurate... you still need to yield return each item of the collection, and Invoke doesn't do it. Here's another version of your method :

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 });
        }
    }
}

Note that I added a constaint on the generic type parameter, and I removed the casts (the way you were doing it, generics didn't bring any benefit)

饮惑 2024-09-03 18:18:17

只是为了清理上面示例中的几个小拼写错误(希望不要添加我自己的拼写错误),这是该示例的最终解决方案。

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;
    }
}

Just to clean up a couple of small typos (and hopefully not add my own) in the above example, here is a final solution to the example.

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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文