Domanda

C # ha qualcosa di simile a __getattr__?

di Python

Ho una classe con molte proprietà e condividono tutte lo stesso codice di accesso. Vorrei essere in grado di eliminare completamente i singoli accessori, proprio come in Python.

Ecco come appare il mio codice ora:

class Foo
{
    protected bool Get(string name, bool def)
    {
        try {
            return client.Get(name);
        } catch {
            return def;
        }
    }

    public bool Bar
    {
        get { return Get("bar", true); }
        set { client.Set("bar", value); }
    }

    public bool Baz
    {
        get { return Get("baz", false); }
        set { client.Set("baz", value); }
    }
}

Ed ecco cosa mi piacerebbe:

class Foo
{
    public bool Get(string name)
    {
        try {
            return client.Get(name);
        } catch {
            // Look-up default value in hash table and return it
        }
    }

    public void Set(string name, object value)
    {
        client.Set(name, value)
    }
}

Esiste un modo per raggiungere questo obiettivo in C # senza chiamare Get direttamente?

Grazie,

È stato utile?

Soluzione

No. Sebbene C # supporti la riflessione, è di sola lettura (per gli assembly caricati). Ciò significa che non è possibile modificare metodi, proprietà o altri metadati. Sebbene potresti creare una proprietà dinamica , chiamarla non sarebbe molto conveniente: sarebbe anche peggio che usare il metodo Get. Oltre a utilizzare un Dictionary<string, object> e un indicizzatore per la tua classe, non c'è molto altro che puoi fare. Ad ogni modo, non è meglio fare un dizionario se hai così tante proprietà?

Python non controlla se esiste un attributo in " compile-time " (o almeno il tempo di caricamento). C # fa. Questa è una differenza fondamentale tra le due lingue. In Python puoi fare:

class my_class:
    pass

my_instance = my_class()
my_instance.my_attr = 1
print(my_instance.my_attr)

In C # non saresti in grado di farlo perché C # controlla effettivamente se il nome my_attr esiste al momento della compilazione.

Altri suggerimenti

Non ne sono sicuro, ma forse le funzionalità dinamiche della versione 4.0 ti aiuteranno. Dovrai aspettare però ...

Posso chiedere: perché non vuoi le singole proprietà? Questo è il modo .NET idiomatico di esprimere i dati associati a un oggetto.

Personalmente, supponendo che i dati non siano scarsi, manterrei le proprietà e farei in modo che il metodo generale utilizzi la riflessione - questo renderà il tuo codice compilato il più velocemente possibile:

    protected T Get<T>(string name, T @default)
    {
        var prop = GetType().GetProperty(name);
        if(prop == null) return @default;
        return (T) prop.GetValue(this, null);
    }

Naturalmente, se non ti interessa che le proprietà stesse vengano definite, un indicizzatore e una ricerca (come il dizionario) andrebbero bene. Ci sono anche cose che potresti essere in grado di fare con postsharp per trasformare un insieme di proprietà in una borsa di proprietà - probabilmente non ne vale la pena, tuttavia.

Se si desidera che le proprietà siano disponibili per l'associazione di dati e il rilevamento di runtime, ma non è possibile definirle in fase di compilazione, è necessario esaminare i descrittori di tipi dinamici; ICustomTypeDescriptor o TypeDescriptionProvider - un bel po 'di lavoro, ma molto versatile (fatemi sapere se volete maggiori informazioni).

Questo non è lo stesso di quello che ottieni in Python con nomi di proprietà dinamici, ma potresti trovarlo utile:

using System;
using System.Collections.Generic;

namespace Program
{
    class Program
    {
        static void Main(string[] args)
        {
            MyList<int> list = new MyList<int>();
            // Add a property with setter.
            list["One"] = 1;
            // Add a property with getter which takes default value.
            int two = list["Two", 2];
            Console.WriteLine("One={0}", list["One"]);
            Console.WriteLine("Two={0} / {1}", two, list["Two"]);
            try
            {
                Console.WriteLine("Three={0}", list["Three"]);
            }
            catch
            {
                Console.WriteLine("Three does not exist.");
            }
        }
        class MyList<T>
        {
            Dictionary<string, T> dictionary = new Dictionary<string,T>();

            internal T this[string property, T def]
            {
                get
                {
                    T value;
                    if (!dictionary.TryGetValue(property, out value))
                        dictionary.Add(property, value = def);
                    return value;
                }
            }
            internal T this[string property]
            {
                get
                {
                    return dictionary[property];
                }
                set
                {
                    dictionary[property] = value;
                }
            }
        }
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top