je travaillais sur ce un peu basé principalement sur la suggestion de Vlad. Il s'avère que pouvez utiliser une seule classe générique pour l'abstraire. Voici le résultat final:
public class Overridable<T>
{
private Func<T> _calculate;
private readonly Func<T, T, bool> _compare;
protected T _t;
public Overridable(Func<T> calculate, Func<T, T, bool> compare)
{
_calculate = calculate;
_compare = compare;
}
public T Value
{
get { return _compare(_t, default(T)) ? _calculate() : _t; }
set { _t = _compare(value, _calculate()) ? default(T) : value; }
}
}
Vous devez passer un délégué de comparer parce que le type ne sait pas jusqu'à ce que vous définissez dans une sous-classe. Donc, un simple ==
ne va pas le couper. Je suis allé le chemin facile et ai utilisé un délégué de Func mais ceci pourrait être remplacé par un délégué normal s'il devait être adapté pour .NET 2.0 pour une certaine raison.
Vous remarquerez que j'utilise default(T)
au lieu de null
. Cela fonctionne parce que la valeur par défaut pour un Nullable<T>
est null
(ou plus précisément, indéfini mais cela revient à être le même).
Cela ne vous empêche pas d'essayer de déclarer un Overridable<T>
pour un type non-nullable. Ce que vous obtiendriez ne se traduira pas par des erreurs de temps d'exécution, mais ce n'est pas aussi utile. Essayer de définir un Overridable<decimal>.Value
à null
vous obtiendrez une erreur de compilation. Lorsque vous le définissez sur default(decimal)
, il revient au calcul de la valeur.
Je suis allé cette route parce que les propriétés de cette classe que je l'utilise dans le besoin de remplir un objet sérialisable qui est finalement transmis en tant que xml. Le schéma pour le xml comprend des champs numériques définis comme un mélange d'entiers, de décimales et de chaînes.
Vous utilisez alors la classe overriddable comme ceci:
private Overridable<decimal?> _excessWages =
new Overridable<decimal?>(CalculateExcessWages, (x,y) => x == y);
public virtual decimal? ExcessWages
{
get
{
return _excessWages.Value;
}
set
{
_excessWages.Value = value;
}
}
Le seul problème que je suis tombé sur c'était que CalculateExcessWages
est une méthode non statique ne peut donc pas être utilisé dans un initialiseur sur le terrain. Comme toutes les propriétés de ma classe ne sont pas statiques, j'ai dû initialiser tous les champs de sauvegarde dans le constructeur.
Qu'est-ce que vous demandez réellement à propos de; Je vois que la propriété est déclarée comme "virtuelle", mais à partir du texte, je comprends que vous demandez plus sur la construction du code à l'intérieur du setter? –
Désolé à ce sujet. J'ai enlevé le virtuel. Ce n'est pas ce qui m'intéresse. Je suis préoccupé par «substituable» du point de vue de l'utilisateur final. –