C#有擴展屬性嗎?

C#有擴展屬性嗎? git

例如,我能夠向DateTimeFormatInfo添加一個名爲ShortDateLongTimeFormat的擴展屬性,它將返回ShortDatePattern + " " + LongTimePattern嗎? github


#1樓

目前,Roslyn編譯器仍然不支持開箱即用......

到目前爲止,擴展屬性被認爲不足以包含在之前版本的C#標準中。 C#7C#8.0已將此視爲提案冠軍,但還沒有發佈,最重要的是由於即便已經有實施,他們也但願從一開始就作到正確。 dom

但它會......

C#7工做列表中有一個擴展成員項,所以可能在不久的未來支持它。 擴展屬性的當前狀態能夠在相關項下的Github上找到。 ui

然而,有一個更有但願的主題是「擴展一切」 ,重點是特別是屬性和靜態類甚至字段。 this

此外,您可使用解決方法

本文所述 ,您可使用TypeDescriptor功能在運行時將屬性附加到對象實例。 可是,它沒有使用標準屬性的語法。
它與語法糖略有不一樣,增長了定義擴展屬性的可能性
string Data(this MyClass instance)做爲擴展方法的別名
string GetData(this MyClass instance)由於它將數據存儲到類中。 spa

我但願C#7能提供全功能的擴展(屬性和字段),可是在這一點上,只有時間會證實。 設計

並隨意貢獻,由於明天的軟件未來自社區。 code

更新:2016年8月 orm

隨着dotnet團隊發佈了C#7.0中的新內容以及Mads Torgensen的評論: xml

擴展屬性:咱們有一個(輝煌!)實習生在夏天實施它們做爲實驗,以及其餘類型的擴展成員。 咱們仍然對此感興趣,但這是一個很大的變化,咱們須要確信這是值得的。

彷佛擴展屬性和其餘成員仍然是將來發布的Roslyn中的好選擇,但可能不是7.0。

更新:2017年5月

擴展成員已被關閉做爲擴展的全部問題的副本也被關閉。 主要的討論其實是廣義上的類型可擴展性。 此功能如今做爲提案進行跟蹤已從7.0里程碑中刪除。

更新:2017年8月 - C#8.0提議的功能

雖然它仍然只是一個提議的功能,但咱們如今能夠更清楚地瞭解它的語法。 請記住,這也是擴展方法的新語法:

public interface IEmployee 
{
    public decimal Salary { get; set; }
}

public class Employee
{
    public decimal Salary { get; set; }
}

public extension MyPersonExtension extends Person : IEmployee
{
    private static readonly ConditionalWeakTable<Person, Employee> _employees = 
        new ConditionalWeakTable<Person, Employee>();


    public decimal Salary
    {
        get 
        {
            // `this` is the instance of Person
            return _employees.GetOrCreate(this).Salary; 
        }
        set 
        {
            Employee employee = null;
            if (!_employees.TryGetValue(this, out employee)
            {
                employee = _employees.GetOrCreate(this);
            }
            employee.Salary = value;
        }
    }
}

IEmployee person = new Person();
var salary = person.Salary;

與部分類相似,但在不一樣的程序集中編譯爲單獨的類/類型。 請注意,您也能夠經過這種方式添加靜態成員和運算符。 如Mads Torgensen播客所述,擴展將不具備任何狀態(所以它沒法將私有實例成員添加到類中),這意味着您將沒法添加連接到該實例的私有實例數據 。 爲此調用的緣由是它意味着管理內部詞典而且可能很難(內存管理等)。 爲此,您仍然可使用前面描述的TypeDescriptor / ConditionalWeakTable技術和屬性擴展,將其隱藏在一個不錯的屬性下。

語法仍然會發生變化,由於這意味着這個問題 。 例如, extends能夠替換for一些可能感受更天然且更少與Java相關的extends

更新2018年12月 - 角色,擴展和靜態接口成員

擴展一切都沒有進入C#8.0,由於一些缺點被解釋爲這個GitHub票的結束。 所以,有一項改進設計的探索。 在這裏 ,Mads Torgensen解釋了什麼是角色和擴展以及它們的區別:

角色容許在給定類型的特定值上實現接口。 擴展容許在特定代碼區域內的給定類型的全部值上實現接口。

在兩個用例中,能夠看出先前提案的拆分。 擴展新語法以下:

public extension ULongEnumerable of ulong
{
    public IEnumerator<byte> GetEnumerator()
    {
        for (int i = sizeof(ulong); i > 0; i--)
        {
            yield return unchecked((byte)(this >> (i-1)*8));
        }
    }
}

而後你就能夠這樣作:

foreach (byte b in 0x_3A_9E_F1_C5_DA_F7_30_16ul)
{
    WriteLine($"{e.Current:X}");
}

對於靜態接口

public interface IMonoid<T> where T : IMonoid<T>
{
    static T operator +(T t1, T t2);
    static T Zero { get; }
}

int上添加擴展屬性並將int視爲IMonoid<int>

public extension IntMonoid of int : IMonoid<int>
{
    public static int Zero => 0;
}

#2樓

由於我最近須要這個,因此我查看了答案的來源:

c#經過添加屬性來擴展類

並建立了一個更動態的版本:

public static class ObjectExtenders
{
    static readonly ConditionalWeakTable<object, List<stringObject>> Flags = new ConditionalWeakTable<object, List<stringObject>>();

    public static string GetFlags(this object objectItem, string key)
    {
        return Flags.GetOrCreateValue(objectItem).Single(x => x.Key == key).Value;
    }

    public static void SetFlags(this object objectItem, string key, string value)
    {
        if (Flags.GetOrCreateValue(objectItem).Any(x => x.Key == key))
        {
            Flags.GetOrCreateValue(objectItem).Single(x => x.Key == key).Value = value;
        }
        else
        {
            Flags.GetOrCreateValue(objectItem).Add(new stringObject()
            {
                Key = key,
                Value = value
            });
        }
    }

    class stringObject
    {
        public string Key;
        public string Value;
    }
}

它可能會改進不少(命名,動態而不是字符串),我目前在CF 3.5中使用它與hacky ConditionalWeakTable( https://gist.github.com/Jan-WillemdeBruyn/db79dd6fdef7b9845e217958db98c4d4


#3樓

正如@Psyonity所提到的,您可使用conditionalWeakTable向現有對象添加屬性。 結合動態ExpandoObject,您能夠在幾行中實現動態擴展屬性:

using System.Dynamic;
using System.Runtime.CompilerServices;

namespace ExtensionProperties
{
    /// <summary>
    /// Dynamically associates properies to a random object instance
    /// </summary>
    /// <example>
    /// var jan = new Person("Jan");
    ///
    /// jan.Age = 24; // regular property of the person object;
    /// jan.DynamicProperties().NumberOfDrinkingBuddies = 27; // not originally scoped to the person object;
    ///
    /// if (jan.Age &lt; jan.DynamicProperties().NumberOfDrinkingBuddies)
    /// Console.WriteLine("Jan drinks too much");
    /// </example>
    /// <remarks>
    /// If you get 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create' you should reference Microsoft.CSharp
    /// </remarks>
    public static class ObjectExtensions
    {
        ///<summary>Stores extended data for objects</summary>
        private static ConditionalWeakTable<object, object> extendedData = new ConditionalWeakTable<object, object>();

        /// <summary>
        /// Gets a dynamic collection of properties associated with an object instance,
        /// with a lifetime scoped to the lifetime of the object
        /// </summary>
        /// <param name="obj">The object the properties are associated with</param>
        /// <returns>A dynamic collection of properties associated with an object instance.</returns>
        public static dynamic DynamicProperties(this object obj) => extendedData.GetValue(obj, _ => new ExpandoObject());
    }
}

一個用法示例在xml註釋中:

var jan = new Person("Jan");

jan.Age = 24; // regular property of the person object;
jan.DynamicProperties().NumberOfDrinkingBuddies = 27; // not originally scoped to the person object;

if (jan.Age < jan.DynamicProperties().NumberOfDrinkingBuddies)
{
    Console.WriteLine("Jan drinks too much");
}

jan = null; // NumberOfDrinkingBuddies will also be erased during garbage collection

#4樓

更新(感謝@chaost指出此更新):

Mads Torgersen: 「擴展全部內容都沒有進入C#8.0。若是你願意的話,它會被」遇上「,在一場關於該語言將來發展的激動人心的辯論中,如今咱們要確保咱們不要以一種抑制將來可能性的方式添加它。有時語言設計是一個很是漫長的遊戲!「

來源: https : //blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/中的評論部分


多年來我一直打開這個問題,但願可以看到這個問題,我已經中止計算了多少次。

好吧,最後咱們都歡喜! 微軟將在他們即將發佈的C#8版本中介紹這一點。

因此不要這樣作......

public static class IntExtensions
{
   public static bool Even(this int value)
   {
        return value % 2 == 0;
   }
}

咱們終於可以這樣作......

public extension IntExtension extends int
{
    public bool Even => this % 2 == 0;
}

資料來源: https//blog.ndepend.com/c-8-0-features-glimpse-future/


#5樓

不,它們不存在於C#3.0中,也不會在4.0中添加。 它位於C#的功能需求列表中,所以可能會在未來添加。

此時,您能夠作的最好的是GetXXX樣式擴展方法。

相關文章
相關標籤/搜索