属性阻塞get直到set如何优雅实现?

发布于 2022-09-07 19:31:22 字数 206 浏览 26 评论 0

一些在程序初始化时交给后台线程异步赋值的属性,完成set之前有可能UI就准备好了,也就是用户可以操作了,操作中如果需要get某个尚未set的属性,我希望代码阻塞,直到set后继续执行,当然如果get之前就已经set好了就无阻塞了。所以这种阻塞最多只用一次,为此专门弄个锁或者信号对象我觉得不地道,这种场景应该很典型,我想知道有没有比较优雅的方式(比如在这种属性上加个[xxx]特性之类)写这种属性?

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

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

发布评论

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

评论(2

街角迷惘 2022-09-14 19:31:22

使用同步事件即可:

private ManualResetEvent _lockEvent = new  ManualResetEvent(false);
private string prop;
public string Prop  {
    get {
        _lockEvent.WaitOne();        
        return prop;
    }
    set {
        prop = value;
        _lockEvent.Set();
    }
}
乖乖哒 2022-09-14 19:31:22

类似这样?但是没有可以直接使用的Attribute,不过可以自己实现一套

using System;
using System.Threading.Tasks;

namespace Test6
{
    class Program
    {
        static void Main(string[] args)
        {
            var t = new Test();
            Console.WriteLine("[" + DateTime.Now.ToString("HH:mm:ss.fff") + "] " + t.NormalProperty);
            //Console.WriteLine("[" + DateTime.Now.ToString("HH:mm:ss.fff") + "] " + t.LazyProperty);
            Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.fff")}] pretending doing something that will takes 3s");
            System.Threading.Thread.Sleep(3000);
            Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.fff")}] something is done in 3s");
            var lazyValue = t.LazyProperty;
            Console.WriteLine("[" + DateTime.Now.ToString("HH:mm:ss.fff") + "] " + lazyValue);
            Console.ReadLine();
        }
    }

    public class Test
    {
        public string NormalProperty { get; set; }
        public string LazyProperty
        {
            get
            {
                //if (GetLazyPropertyValue.IsCompleted)
                //{
                    return GetLazyPropertyValue.Result;
                //}
                //else
                //{
                //    return "LazyProperty uninitialized";
                //}
            }
        }

        public Test()
        {
            this.NormalProperty = "NormalProperty";
            GetLazyPropertyValue.Start();
        }

        protected Task<string> GetLazyPropertyValue = new Task<string>(() =>
        {
            System.Threading.Thread.Sleep(5000);
            return "LazyProperty initialized";
        });
    }
}

升了个级,加上了Attribute

using System;
using System.Dynamic;
using System.Reflection;
using System.Threading.Tasks;

namespace Test6
{
    class Program
    {
        static void Main(string[] args)
        {
            dynamic t = new DynamicProxy(new Test());
            Console.WriteLine("[" + DateTime.Now.ToString("HH:mm:ss.fff") + "] " + t.NormalProperty);
            Console.WriteLine("[" + DateTime.Now.ToString("HH:mm:ss.fff") + "] " + t.LazyPropertyWithDefaultValue);
            Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.fff")}] pretending doing something that will takes 3s");
            System.Threading.Thread.Sleep(3000);
            Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.fff")}] something is done in 3s");
            var lazyValue = t.LazyProperty;
            Console.WriteLine("[" + DateTime.Now.ToString("HH:mm:ss.fff") + "] " + lazyValue);
            Console.WriteLine("[" + DateTime.Now.ToString("HH:mm:ss.fff") + "] " + t.LazyPropertyWithDefaultValue);
            Console.ReadLine();
        }
    }

    [LazyPropertyIncluded]
    public class Test
    {
        public string NormalProperty { get; set; }

        [LazyProperty(InitializerName = "InitLazyProperty")]
        public string LazyProperty { get; }

        [LazyProperty(HasDefaultValue =true, Defaultalue = "LazyPropertyWithDefaultValue Default Value")]
        public string LazyPropertyWithDefaultValue { get; }

        protected Task<string> InitLazyProperty = new Task<string>(() =>
        {
            Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.fff")}] start initializing LazyProperty");
            System.Threading.Thread.Sleep(5000);
            return "LazyProperty initialized";
        });

        protected Task<string> InitLazyPropertyWithDefaultValue = new Task<string>(() =>
        {
            Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.fff")}] start initializing LazyPropertyWithDefaultValue");
            System.Threading.Thread.Sleep(5000);
            return "LazyPropertyWithDefaultValue initialized";
        });

        public Test()
        {
            this.NormalProperty = "NormalProperty";
        }
    }

    [AttributeUsage(AttributeTargets.Property)]
    public class LazyPropertyAttribute : Attribute
    {
        public string InitializerName { get; set; }
        public bool HasDefaultValue { get; set; }
        public object Defaultalue { get; set; }
    }

    [AttributeUsage(AttributeTargets.Class)]
    public class LazyPropertyIncludedAttribute : Attribute { }

    public class DynamicProxy : DynamicObject
    {
        readonly object[] _sources;

        public DynamicProxy(params object[] sources)
        {
            this._sources = sources;

            // run init method for lazy properties
            foreach (var src in this._sources)
            {
                var attr = src.GetType().GetCustomAttribute<LazyPropertyIncludedAttribute>();
                if (attr != null)
                {
                    foreach (var prop in src.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
                    {
                        var propAttr = prop.GetCustomAttribute<LazyPropertyAttribute>();
                        if (propAttr != null)
                        {
                            var initTask = propAttr.InitializerName ?? "Init" + prop.Name;
                            var task = src.GetType().GetField(initTask, BindingFlags.Instance | BindingFlags.NonPublic);
                            if (task != null)
                            {
                                ((Task)task.GetValue(src)).Start();
                            }
                            else
                            {
                                throw new MethodAccessException("Cannot find initialization method [" + initTask + "] for lazy prop: " + prop.Name);
                            }
                        }
                    }
                }
            }
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            object propValue = null;

            foreach (var src in this._sources)
            {
                var prop = src.GetType().GetProperty(binder.Name);
                if (prop != null)
                {
                    var propAttr = prop.GetCustomAttribute<LazyPropertyAttribute>();
                    if (propAttr == null)
                    {
                        propValue = prop.GetValue(src);
                    }
                    else
                    {
                        var initTask = propAttr.InitializerName ?? "Init" + prop.Name;
                        var task = src.GetType().GetField(initTask, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(src) as Task;
                        if (!task.IsCompleted && propAttr.HasDefaultValue)
                        {
                            propValue = propAttr.Defaultalue;
                        }
                        else
                        {
                            Task.WaitAll(task);
                            propValue = Convert.ChangeType(task.GetType().GetProperty("Result").GetValue(task), prop.PropertyType);
                        }
                    }
                    break;
                }
            }

            if (propValue == null)
            {
                propValue = binder.Name + " from dynamic proxy";
            }

            result = propValue;

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