鍍金池/ 問答/Java  C#  網(wǎng)絡安全  HTML/ 屬性阻塞get直到set如何優(yōu)雅實現(xiàn)?

屬性阻塞get直到set如何優(yōu)雅實現(xiàn)?

一些在程序初始化時交給后臺線程異步賦值的屬性,完成set之前有可能UI就準備好了,也就是用戶可以操作了,操作中如果需要get某個尚未set的屬性,我希望代碼阻塞,直到set后繼續(xù)執(zhí)行,當然如果get之前就已經set好了就無阻塞了。所以這種阻塞最多只用一次,為此專門弄個鎖或者信號對象我覺得不地道,這種場景應該很典型,我想知道有沒有比較優(yōu)雅的方式(比如在這種屬性上加個[xxx]特性之類)寫這種屬性?

回答
編輯回答
不討囍

使用同步事件即可:

private ManualResetEvent _lockEvent = new  ManualResetEvent(false);
private string prop;
public string Prop  {
    get {
        _lockEvent.WaitOne();        
        return prop;
    }
    set {
        prop = value;
        _lockEvent.Set();
    }
}
2017年7月28日 04:45
編輯回答
櫻花霓

類似這樣?但是沒有可以直接使用的Attribute,不過可以自己實現(xiàn)一套

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;
        }
    }
}
2017年9月5日 05:56