2012-05-18 6 views
9

Il team C# ha in precedenza considerato di aggiungere proprietà di estensione, eventi ecc. A C#.Stato di conservazione in un metodo di estensione

Per Eric Lippert:

http://blogs.msdn.com/b/ericlippert/archive/2009/10/05/why-no-extension-properties.aspx

Per queste caratteristiche per essere utili tuttavia, dovrebbe essere in grado di memorizzare un nuovo tipo di stato con un oggetto. Sembra che l'unico modo per farlo sarebbe quello di usare un dizionario e associare ogni istanza di un oggetto con qualunque sia lo stato aggiuntivo.

Sarebbe utile se fosse possibile copiare questa funzionalità "manualmente" creando il mio dizionario (e magari ottenere/impostare metodi di estensione). Tuttavia, al fine di associare una particolare istanza di un oggetto con uno stato, è necessario eseguire l'hash dell'oggetto effettivo. In un'altra lingua si potrebbe fare questo triturando la sua posizione di memoria, tuttavia in C# non è garantito che rimanga costante, e l'uso di codice non sicuro per realizzare questa funzione è comunque lontano dall'ideale.

Qualcuno sa se è possibile ottenere un riferimento hashable a un oggetto che non cambia quando lo stato interno dell'oggetto cambia? Esiste ovviamente un meccanismo interno per tenere traccia dei singoli oggetti indipendentemente dalla loro posizione di memoria, ma non sono sicuro che sia esposto al codice utente.

Nota: l'hash stesso dell'oggetto non funzionerà affatto, poiché GetHashCode() dipende dallo stato interno di un oggetto non su quale oggetto è.

Grazie per qualsiasi intuizione.

+1

Ugh, mi piace metodi di estensione perché non trattano con lo stato dell'oggetto e sono solo lo zucchero sintassi, avrei paura di fare qualcosa di più in realtà sfuma i linee troppo ...Detto questo, è un pensiero interessante, ovviamente ... –

risposta

11

Stai cercando il ConditionalWeakTable class.

+3

Wow. Un altro caso di "Dopo 10 anni di C#, continuo a scoprire cose". Grazie. –

+1

@KooKiz: prova la classe 'PluralizationService' – SLaks

+0

Sono anche stupito di non averlo visto prima. Sembra che funzioni agendo su un oggetto e chiamando RuntimeHelpers.GetHashCode(), (che fa un po 'di magia di runtime). Conoscete le implicazioni sulle prestazioni dell'uso di questa classe? – MgSam

0

** INTERO QUALSIASI MODO ** Le proprietà sono mantenute in un dizionario che utilizza un riferimento debole agli oggetti come chiavi e una dizione con coppie di oggetti stringa per memorizzare le proprietà e i relativi valori.

Per impostare, ottenere o eliminare proprietà per un oggetto, l'oggetto è cercare nei riferimenti deboli nel dizionario.

ci possono essere due modi per smaltire le proprietà non utilizzati:

  • controllo della IsAlive del riferimento debole, e rimuovere la voce nel dizionario se falsa
  • implementare IDisposable nel "estensibile "oggetti e chiama un metodo di estensione che rimuove le proprietà sull'oggetto che si sta disponendo.

Ho incluso un blocco utilizzando opzionale nel codice di esempio, in modo che è possibile eseguire il debug e vedere come Dispose chiama il metodo di estensione RemoveProperties. Questo è ovviamente facoltativo e il metodo sarebbe chiamato quando l'oggetto è GC.

Esempio di lavoro dell'idea, utilizzo di WeakReference, dizionari statici e IDisposable.

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace ConsoleApplication3 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      using (PropertyLessClass plc = new PropertyLessClass()) 
      { 
       plc.SetProperty("age", 25); 
       plc.SetProperty("name", "John"); 
       Console.WriteLine("Age: {0}", plc.GetProperty("age")); 
       Console.WriteLine("Name: {0}", plc.GetProperty("name")); 
      } 
      Console.ReadLine(); 
     } 
    } 
} 

public class PropertyLessClass : IDisposable 
{ 
    public void Dispose() 
    { 
     this.DeleteProperties(); 
    } 
} 

public static class PropertyStore 
{ 
    private static Dictionary<WeakReference, Dictionary<string, object>> store 
     = new Dictionary<WeakReference, Dictionary<string, object>>(); 

    public static void SetProperty(this object o, string property, object value) 
    { 
     var key = store.Keys.FirstOrDefault(wr => wr.IsAlive && wr.Target == o); 
     if (key == null) 
     { 
      key = new WeakReference(o); 
      store.Add(key, new Dictionary<string, object>()); 
     } 
     store[key][property] = value; 
    } 

    public static object GetProperty(this object o, string property) 
    { 
     var key = store.Keys.FirstOrDefault(wr => wr.IsAlive && wr.Target == o); 
     if (key == null) 
     { 
      return null; // or throw Exception 
     } 
     if (!store[key].ContainsKey(property)) 
      return null; // or throw Exception 
     return store[key][property]; 
    } 

    public static void DeleteProperties(this object o) 
    { 
     var key = store.Keys.FirstOrDefault(wr => wr.IsAlive && wr.Target == o); 
     if (key != null) 
     { 
      store.Remove(key); 
     } 
    } 
} 
+0

Penso che tu abbia frainteso la domanda. – MgSam

+0

Penso di sì. Ho aggiunto del testo alla mia risposta. – JotaBe

+0

Grazie per la risposta. Un problema con questo codice è che utilizza stringhe magiche debolmente tipizzate per rappresentare i nomi delle proprietà. Con i metodi di estensione sulla classe stessa è possibile eseguire metodi get/set che non soffrono di questo problema. – MgSam