1. 程式人生 > >永利國際源碼下載

永利國際源碼下載

判斷 嘗試 etc class 屬性設置 urn 應用 bloom .com

永利國際源碼下
地址一:【hubawl.com】狐霸源碼論壇
地址二:【bbscherry.com】

由於采用字典的方式來保存屬性變更值的底層設計思想,導致了性能問題,雖然.NET的字典實現已經很高效了,但相對於直接讀寫字段的方式而言依然有巨大的性能差距,同時也會導致對屬性的讀寫過程中產生不必要的裝箱和拆箱。
那麽這次我們就來徹底解決這個問題,同時還要解決“哪些屬性發生過變更”、“獲取變更的屬性集”這些功能特性,所以我們先把接口定義出來,以便後續問題講解。

/ 源碼位於 Zongsoft.CoreLibary 項目的 Zongsoft.Data 命名空間中 /

/// <summary> 表示數據實體的接口。</summary>

public interface IEntity
{
/// <summary>
/// 判斷指定的屬性或任意屬性是否被變更過。
/// </summary>
/// <param name="names">指定要判斷的屬性名數組,如果為空(null)或空數組則表示判斷任意屬性。</param>
/// <returns>
/// <para>如果指定的<paramref name="names"/>參數有值,當只有參數中指定的屬性發生過更改則返回真(True),否則返回假(False);</para>
/// <para>如果指定的<paramref name="names"/>參數為空(null)或空數組,當實體中任意屬性發生過更改則返回真(True),否則返回假(False)。</para>
/// </returns>
bool HasChanges(params string[] names);

/// <summary>
/// 獲取實體中發生過變更的屬性集。
/// </summary>
/// <returns>如果實體沒有屬性發生過變更,則返回空(null),否則返回被變更過的屬性鍵值對。</returns>
IDictionary<string, object> GetChanges();

/// <summary>
/// 嘗試獲取指定名稱的屬性變更後的值。
/// </summary>
/// <param name="name">指定要獲取的屬性名。</param>
/// <param name="value">輸出參數,指定屬性名對應的變更後的值。</param>
/// <returns>如果指定名稱的屬性是存在的並且發生過變更,則返回真(True),否則返回假(False)。</returns>
/// <remarks>註意:即使指定名稱的屬性是存在的,但只要其值未被更改過,也會返回假(False)。</remarks>
bool TryGetValue(string name, out object value);

/// <summary>
/// 嘗試設置指定名稱的屬性值。
/// </summary>
/// <param name="name">指定要設置的屬性名。</param>
/// <param name="value">指定要設置的屬性值。</param>
/// <returns>如果指定名稱的屬性是存在的並且可寫入,則返回真(True),否則返回假(False)。</returns>
bool TrySetValue(string name, object value);

}
設計思想
根本要點是取消用字典來保存屬性值回歸到字段方式,只有這樣才能確保性能,關鍵問題是如何在寫入字段值的時候,標記對應的屬性發生過變更的呢?應用布隆過濾器(Bloom Filter)算法的思路來處理這個應用場景是一個完美的解決方案,因為布隆過濾器的空間效率和查詢效率極高,而它的缺點在此恰好可以針對性的優化掉。

將每個屬性映射到一個整型數(byte/ushort/uint/ulong)的某個比特位(bit),如果發生過變更則將該 bit 置為 1,只要確保屬性與二進制位順序是確定的即可,算法復雜度是O(1)常量,並且比特位操作的效率也是極高的。

實現示範
有了算法,我們寫一個簡單範例來感受下:

public class Person : IEntity
{
#region 靜態字段
private static readonly string[] NAMES = new string[] { "Name", "Gender", "Birthdate" };
private static readonly Dictionary<string, PropertyToken<Person>> TOKENS = new Dictionary<string, PropertyToken<Person>>()
{
{ "Name", new PropertyToken<Person>(0, target => target._name, (target, value) => target.Name = (string) value) },
{ "Gender", new PropertyToken<Person>(1, target => target._gender, (target, value) => target.Gender = (Gender?) value) },
{ "Birthdate", new PropertyToken<Person>(2, target => target._birthdate, (target, value) => target.Birthdate = (DateTime) value) },
};
#endregion

#region 標記變量
private byte _MASK_;
#endregion

#region 成員字段
private string _name;
private bool? _gender;
private DateTime _birthdate;
#endregion

#region 公共屬性
public string Name
{
    get => _name;
    set
    {
        _name = value;
        _MASK_ |= 1;
    }
}

public bool? Gender
{
    get => _gender;
    set
    {
        _gender = value;
        _MASK_ |= 2;
    }
}

public DateTime Birthdate
{
    get => _birthdate;
    set
    {
        _birthdate = value;
        _MASK_ |= 4;
    }
}
#endregion

#region 接口實現
public bool HasChanges(string[] names)
{
    PropertyToken<Person> property;

    if(names == null || names.Length == 0)
        return _MASK_ != 0;

    for(var i = 0; i < names.Length; i++)
    {
        if(__TOKENS__.TryGetValue(names[i], out property) && (_MASK_ >> property.Ordinal & 1) == 1)
            return true;
    }

    return false;
}

public IDictionary<string, object> GetChanges()
{
    if(_MASK_ == 0)
        return null;

    var dictionary = new Dictionary<string, object>(__NAMES__.Length);

    for(int i = 0; i < __NAMES__.Length; i++)
    {
        if((_MASK_ >> i & 1) == 1)
            dictionary[__NAMES__[i]] = __TOKENS__[__NAMES__[i]].Getter(this);
    }

    return dictionary;
}

public bool TryGetValue(string name, out object value)
{
    value = null;

    if(__TOKENS__.TryGetValue(name, out var property) && (_MASK_ >> property.Ordinal & 1) == 1)
    {
        value = property.Getter(this);
        return true;
    }

    return false;
}

public bool TrySetValue(string name, object value)
{
    if(__TOKENS__.TryGetValue(name, out var property))
    {
        property.Setter(this, value);
        return true;
    }

    return false;
}
#endregion

}

// 輔助結構
public struct PropertyToken<T>
{
public PropertyToken(int ordinal, Func<T, object> getter, Action<T, object> setter)
{
this.Ordinal = ordinal;
this.Getter = getter;
this.Setter = setter;
}

public readonly int Ordinal;
public readonly Func<T, object> Getter;
public readonly Action<T, object> Setter;

}
上面實現代碼,主要有以下幾個要點:

屬性設置器中除了對字段賦值外,多了一個位或賦值操作(這是一句非常低成本的代碼);
需要一個額外的整型數的實例字段 MASK ,來標記對應更改屬性序號;
分別增加 NAMES TOKENS 兩個靜態只讀變量,來保存實體類的元數據,以便更高效的實現 IEntity接口方法。
根據代碼可分析出其理論執行性能與原生實現基本一致,內存消耗只多了一個字節(如果可寫屬性數量小於9),由於 NAMESTOKENS 是靜態變量,因此不占用實例空間,理論上該方案的整體效率非常高。

永利國際源碼下載