先前使用拆解字串的方式,雖然達到了加速的效果,不過要是在Property的Getter跟Setter以外的地方去call,
那就是無法得到property name了....
因此,我想先確認Property Getter與Setter的Method Name是否有任何識別方式,
首先,我確認的是Getter Name會像"<get_PropertyName>b_0"之類,Setter Name會像"<set_PropertyName>b_2"之類,
後面的b_0跟b_2抓不準規則,但是<get_PropertyName>與<set_PropertyName>似乎是識別項

minuswu 發表在 痞客邦 留言(0) 人氣()

大概在12月初,自己的系統寫到了需要在裡面寫Code,即時編譯執行的部分,
對於記憶力薄弱的我來說,Visual Studio的Intellisense真的是我的救星,
這次我挑了AvalonEditor來做為我的Editor,雖然有已有C# Highlight的功能,
但卻沒有Intellisense啊!
看過了一些其它例子後,似乎沒有很簡單合用的,但不如自己來?
根據MDA,先來個自我需求訪談吧,Intellisense 的需求列表:
(1) 在.字元輸入後,可帶出前方所描述片段之Type, Member 或Variable 的 Member List
    => 前方描述片段的終點應為往回推至空白、Tab、換行字元出現
(2) ....
沒了?想到再補吧
再展開了一陣子實驗後,發現自己真的是太天真囉,雖然需求只有一點,要想的事情還真不少:
(1) 取得前方描述片段 => 一個一個char推回去就可以找到
(2) 列出前方描述片段的成員:
    [1] 記錄使用到的NameSpace所有Type => 用Reflection載入,目前做到需要事先定義有哪些Namespace,符合我目前的應用範圍
    [2] 假設前方描述片段為Namespace,取得Sub Namespace或Type => [1] 所記錄的形式必須為Tree
    [3] 假設前方描述片段為Namespace + Type,取得Member => [1]所記錄的形式必須為Tree
    [4] 假設前方描述片段為Member,先取得該Memeber的Type => How to ?
    [5] 假設前方描述片段為Variable,先取得該Variable的Type => How to ?
    [6] 顯示列出的Member的Description => How to ?
在此先筆記下來

minuswu 發表在 痞客邦 留言(0) 人氣()


如果我想快速創造一個Entity內含若干Property,但是又不想使用field跟先前所使用的字串來做為get, set value的index,
但是測試過使用Reflection的方式取得Property name,效率非常不好,是否有更有效率的方式呢?
首先,我的目標是在Get跟Set使用下面方式表達
 
        public int Volume
        {
            get { return this.GetValue(e => e.Volume); }
            set { this.SetValue(e => e.Volume, value); }
        }

minuswu 發表在 痞客邦 留言(0) 人氣()

之前寫了一組物件,裡面需要依賴Reflection來取得指定的PropertyInfo,方式如下:
typeof(T).GetProperty(memberExpr.Member.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
在試用一陣子後都平安無事,但是事情不是憨人想得那麼簡單的/_\
在一次遇上必須取得某Interface的Base Interface的PropertyInfo時,這方式失靈了,老是傳回null....
到底是怎麼回事???只好來個測試了,程式碼如下:
    class Program
    {
        public interface IPerson
        {
            string Name { get; set; }
        }
        public interface IContact : IPerson
        {
            string Address { get; set; }
        }
        public class Person : IPerson
        {
            public string Name { get; set; }
        }
        public class Contact : IContact
        {
            public string Name { get; set; }
            public string Address { get; set; }
        }
        public class Customer : Contact
        {
        }
        static void Main(string[] args)
        {
            Console.WriteLine(ToString(GetProperty<IPerson>("Name")));
            Console.WriteLine(ToString(GetProperty<Person>("Name")));
            Console.WriteLine(ToString(GetProperty<IContact>("Name")));
            Console.WriteLine(ToString(GetProperty<Contact>("Name")));
            Console.WriteLine(ToString(GetProperty<Customer>("Name")));
            Console.ReadLine();
        }
        private static string ToString(PropertyInfo property)
        {
            return property == null ? "null" : property.Name;
        }
        public static PropertyInfo GetProperty<T>(string name)
        {
            return typeof(T).GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
        }
    }
得到的結果是只有GetProperty<IContact>("Name")傳回null啊!看來只好為了Interface特別處理了....
針對Type增加Extension Methods

minuswu 發表在 痞客邦 留言(0) 人氣()

檢查參數一直是一件很繁複的事情,尤其拋出ArgumentException要傳入的Parameter Name字串常常讓我感到不舒服,但一直沒有其它辦法可以解決我的問題....
終於在今天請訪Google大神時,找到了透過Expression拆解及IL Parsing手段來取得Variable Name的方法,Happy~
整個Method很簡單:
 
static string GetParamNameByExpression<T>(Expression<Func<T>> expression) 
{
    var body = ((MemberExpression)expression.Body); 
    return body.Member.Name; 
}
 
static string GetParamNameByIL<T>(Func<T> func)
{
    var ilByteArray = func.Method.GetMethodBody().GetILAsByteArray();
    var fieldHandle = BitConverter.ToInt32(ilByteArray, 2);
    return func.Target.GetType().Module.ResolveField(fieldHandle).Name;  
}
使用方式就像GetParamNameByExpression(() => test);不過如果像傳入 () => 1+1,如預料是會拋出Exception的。
經過測試後,這兩個方法的效能差異並不明顯。
使用Expression的方法真是早該想到了,Lambda真是好物啊!

minuswu 發表在 痞客邦 留言(0) 人氣()

今天再修Bug時,有一個Bug是A generic error occurred in GDI+.,讓人摸不著頭緒,後來發現似乎跟Memory不足有相關,這時才發現目前的ListBox為了DataBinding,直接取用Model的Image file path,當來源圖檔過大時,會造成大量Memory損耗,托Google大神所賜,得知了BitmapImage的DecodePixelWidth與DecodePixcelHeight這項利器,再透過Convert轉換終於完成真正帶有縮圖的ListBox啦!
原始碼:待補

minuswu 發表在 痞客邦 留言(0) 人氣()

最近開始重複利用先前寫的底層,於是又思考了Property的Getter與Setter是否可以有更好的設計?
先前的設計是使用static field來記錄Property的基本資訊,為了避免日後造成麻煩,因此使用Expression做為Constructor參數,再透過Expression拆解,取出Property Name,建立Dictionary來存放Property value。
使得Property的宣告看起來大概就像
 
static Property<T, bool> _IsValid = RegisterProperty<bool>(entity => entity.IsValid, "是否合法");
public bool IsValid
{
    get { return this.GetProperty(_IsValid); }
    private set { this.SetProperty(_IsValid, value); }
}
我第一個想法是想要把GetProperty<P>(Property<T, P>)改為GetProperty<P>(Expression<Func<T, P>> property),直接拿Expression當Dictionary Key,但是結果發現每次都會產生新的Expression Instance,還真是不意外....
那麼如果將GetProperty & SetProperty改為每次拆解Expression呢?
實驗開始,先大概寫出底層的樣子
public class Entity<T> where T :Entity<T>
{
    private ConcurrentDictionary<string, object> _Properties;
    public string Name
    {
        get;
        set;
    }
    public string NameByDictionary
    {
        get { return (string)this._Properties["Name"]; }
        set { this._Properties.AddOrUpdate("Name", value, (key, v) => v); }
    }
    public string NameByExpressionName
    {
        get { return (string)this.GetPropertyByName(entity => entity.Name); }
        set { this.SetPropertyByName(entity => entity.Name, value); }
    }
    public Entity()
    {
        this._Properties = new ConcurrentDictionary<string, object>();
    }
    public P GetPropertyByName<P>(Expression<Func<T, P>> property)
    {
        var member = GetMember(property);
        return (P)this._Properties[member.Name];
    }
    public void SetPropertyByName<P>(Expression<Func<T, P>> property, P newValue)
    {
        var member = GetMember(property);
        this._Properties[member.Name] = newValue;
    }
    public static MemberInfo GetMember<P>(Expression<Func<T, P>> member)
    {
        if (member.Body.NodeType == ExpressionType.MemberAccess)
        {
            return ((MemberExpression)member.Body).Member;
        }
        throw new ArgumentException("Not a member access", "member");
    }
}

minuswu 發表在 痞客邦 留言(0) 人氣()

1
Blog Stats
⚠️

成人內容提醒

本部落格內容僅限年滿十八歲者瀏覽。
若您未滿十八歲,請立即離開。

已滿十八歲者,亦請勿將內容提供給未成年人士。