C # ha proprietà di estensione?

C # ha proprietà di estensione?

Ad esempio, posso aggiungere una proprietà di estensione a DateTimeFormatInfo chiamato ShortDateLongTimeFormat che restituirebbe ShortDatePattern + " " + LongTimePattern ?

No, non esistono in C # 3.0 e non saranno aggiunti in 4.0. È presente nell’elenco delle funzionalità desiderate per C # in modo che possa essere aggiunto in una data futura.

A questo punto, il meglio che puoi fare è usare i metodi di estensione in stile GetXXX.

No, non esistono.

So che il team C # li stava prendendo in considerazione a un certo punto (o almeno Eric Lippert era) – insieme ai costruttori e agli operatori di estensioni (potrebbero volerci un po ‘di tempo per girare la testa, ma sono fantastici …) Tuttavia, ho rifugio Non ho visto alcuna prova che faranno parte del C # 4.

EDIT: non apparivano in C # 5, e a partire da luglio 2014 non sembra che sarà in C # 6.

Eric Lippert , il principale sviluppatore del team di compilatori C # di Microsoft fino a novembre 2012, ne ha parlato in ottobre nell’ottobre 2009:

  • Perché nessuna proprietà di estensione? – Favolose avventure nella codifica

Per il momento non è ancora supportato dal compilatore Roslyn …

Fino ad ora, le proprietà dell’estensione non erano considerate sufficientemente valide da essere incluse nelle versioni precedenti dello standard C # (ovvero 5 e 6).

Ma lo farà …

C’è un elemento di membri di estensione nella lista di lavoro C # 7 in modo che possa essere supportato nel prossimo futuro. Lo stato corrente della proprietà dell’estensione può essere trovato su Github sotto l’elemento correlato .

Tuttavia, c’è un argomento ancora più promettente che è il “estendere tutto” con particolare attenzione alle proprietà e alle classi statiche o persino ai campi.

Inoltre è ansible utilizzare una soluzione alternativa

Come specificato in questo articolo , è ansible utilizzare la funzionalità TypeDescriptor per colbind un attributo a un’istanza dell’object in fase di esecuzione. Tuttavia, non sta usando la syntax delle proprietà standard.
È un po ‘diverso dal semplice zucchero sintattico, aggiungendo la possibilità di definire una proprietà estesa come
string Data(this MyClass instance) come alias per il metodo di estensione
string GetData(this MyClass instance) mentre memorizza i dati nella class.

Spero che C # 7 fornisca un’estensione completa di tutte le funzionalità (proprietà e campi), tuttavia su quel punto, solo il tempo lo dirà.

E sentiti libero di contribuire poiché il software di domani verrà dalla comunità.

Aggiornamento: agosto 2016

Come squadra dotnet ha pubblicato le novità in C # 7.0 e da un commento di Mads Torgensen :

Proprietà di estensione: abbiamo avuto un (brillante!) Stagista implementarle durante l’estate come esperimento, insieme ad altri tipi di membri di estensione. Rimaniamo interessati a questo, ma è un grande cambiamento e dobbiamo sentirci sicuri che ne valga la pena.

Sembra che le proprietà di estensione e altri membri siano ancora buoni candidati da includere in una versione futura di Roslyn, ma forse non quella di 7.0.

Aggiornamento: maggio 2017

I membri dell’estensione sono stati chiusi come duplicati dell’estensione di tutto il problema che è anch’esso chiuso. La discussione principale riguardava infatti l’estensibilità di tipo in senso lato. La funzione è ora tracciata qui come proposta ed è stata rimossa dalla pietra miliare 7.0 .

Aggiornamento: agosto 2017 – C # 8.0 funzionalità proposta

Sebbene rimanga solo una caratteristica proposta , ora abbiamo una visione più chiara di quale sarebbe la sua syntax. Tieni presente che questa sarà la nuova syntax anche per i metodi di estensione:

 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 _employees = new ConditionalWeakTable(); 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; 

Simile alle classi parziali, ma compilato come class / tipo separato in un assembly diverso. Nota che sarai anche in grado di aggiungere membri e operatori statici in questo modo. Come accennato nel podcast di Mads Torgensen , l’estensione non avrà alcun stato (quindi non può aggiungere membri di istanze private alla class), il che significa che non sarà ansible aggiungere dati di istanze private collegate all’istanza . La ragione invocata per questo è che implicherebbe la gestione di dizionari interni e potrebbe essere difficile (gestione della memoria, ecc …). Per fare ciò, è ancora ansible utilizzare la tecnica TypeDescriptor / ConditionalWeakTable descritta in precedenza e con l’estensione della proprietà, nascosta sotto una bella proprietà.

La syntax è ancora soggetta a modifiche in quanto implica questo problema . Ad esempio, potrebbero essere sostituiti i extends for quali alcuni potrebbero sentirsi più naturali e meno legati alla java.

Ho smesso di contare quante volte nel corso degli anni ho aperto questa domanda con la speranza di averlo visto implementato.

Bene, finalmente possiamo tutti gioire! Microsoft introdurrà questo nel loro rilascio C # 8.

Quindi invece di fare questo …

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

Saremo finalmente in grado di farlo in questo modo …

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

Fonte: https://blog.ndepend.com/c-8-0-features-glimpse-future/

Come menzionato @Psyonity, puoi usare il parametro ConditionalWeakTable per aggiungere proprietà agli oggetti esistenti. In combinazione con il dinamico ExpandoObject, è ansible implementare le proprietà dell’estensione dynamic in poche righe:

 using System.Dynamic; using System.Runtime.CompilerServices; namespace ExtensionProperties { ///  /// Dynamically associates properies to a random object instance ///  ///  /// 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"); ///  ///  /// If you get 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create' you should reference Microsoft.CSharp ///  public static class ObjectExtensions { ///Stores extended data for objects private static ConditionalWeakTable extendedData = new ConditionalWeakTable(); ///  /// Gets a dynamic collection of properties associated with an object instance, /// with a lifetime scoped to the lifetime of the object ///  /// The object the properties are associated with /// A dynamic collection of properties associated with an object instance. public static dynamic DynamicProperties(this object obj) => extendedData.GetValue(obj, _ => new ExpandoObject()); } } 

Un esempio di utilizzo è nei commenti 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 

Perché di recente ho avuto bisogno di questo, ho guardato la fonte della risposta in:

c # estende la class aggiungendo proprietà

e ha creato una versione più dynamic:

 public static class ObjectExtenders { static readonly ConditionalWeakTable> Flags = new ConditionalWeakTable>(); 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; } } 

Probabilmente può essere migliorato molto (denominazione, dynamic invece di stringa), attualmente lo uso in CF 3.5 insieme a un hacker ConditionalWeakTable ( https://gist.github.com/Jan-WillemdeBruyn/db79dd6fdef7b9845e217958db98c4d4 )