J’essaie de faire ce qui suit:
GetSsortingng( inputSsortingng, ref Client.WorkPhone) private void GetSsortingng(ssortingng inValue, ref ssortingng outValue) { if (!ssortingng.IsNullOrEmpty(inValue)) { outValue = inValue; } }
Cela me donne une erreur de compilation. Je pense que c’est assez clair ce que j’essaie de réaliser. En gros, je veux que GetSsortingng
copie le contenu d’une chaîne d’entrée dans la propriété WorkPhone
du Client
.
Est-il possible de passer une propriété par référence?
Les propriétés ne peuvent pas être transmises par référence. Voici quelques façons de contourner cette limitation.
ssortingng GetSsortingng(ssortingng input, ssortingng output) { if (!ssortingng.IsNullOrEmpty(input)) { return input; } return output; } void Main() { var person = new Person(); person.Name = GetSsortingng("test", person.Name); Debug.Assert(person.Name == "test"); }
void GetSsortingng(ssortingng input, Action setOutput) { if (!ssortingng.IsNullOrEmpty(input)) { setOutput(input); } } void Main() { var person = new Person(); GetSsortingng("test", value => person.Name = value); Debug.Assert(person.Name == "test"); }
void GetSsortingng(ssortingng input, T target, Expression> outExpr) { if (!ssortingng.IsNullOrEmpty(input)) { var expr = (MemberExpression) outExpr.Body; var prop = (PropertyInfo) expr.Member; prop.SetValue(target, input, null); } } void Main() { var person = new Person(); GetSsortingng("test", person, x => x.Name); Debug.Assert(person.Name == "test"); }
void GetSsortingng(ssortingng input, object target, ssortingng propertyName) { if (!ssortingng.IsNullOrEmpty(input)) { prop = target.GetType().GetProperty(propertyName); prop.SetValue(target, input); } } void Main() { var person = new Person(); GetSsortingng("test", person, nameof(Person.Name)); Debug.Assert(person.Name == "test"); }
sans dupliquer la propriété
void Main() { var client = new Client(); NullSafeSet("test", s => client.Name = s); Debug.Assert(person.Name == "test"); NullSafeSet("", s => client.Name = s); Debug.Assert(person.Name == "test"); NullSafeSet(null, s => client.Name = s); Debug.Assert(person.Name == "test"); } void NullSafeSet(ssortingng value, Action setter) { if (!ssortingng.IsNullOrEmpty(value)) { setter(value); } }
J’ai écrit un wrapper en utilisant la variante ExpressionTree et c # 7 (si quelqu’un est intéressé):
public class Accessor { private Action Setter; private Func Getter; public Accessor(Expression> expr) { var memberExpression = (MemberExpression)expr.Body; var instanceExpression = memberExpression.Expression; var parameter = Expression.Parameter(typeof(T)); if (memberExpression.Member is PropertyInfo propertyInfo) { Setter = Expression.Lambda>(Expression.Call(instanceExpression, propertyInfo.GetSetMethod(), parameter), parameter).Comstack(); Getter = Expression.Lambda>(Expression.Call(instanceExpression, propertyInfo.GetGetMethod())).Comstack(); } else if (memberExpression.Member is FieldInfo fieldInfo) { Setter = Expression.Lambda>(Expression.Assign(memberExpression, parameter), parameter).Comstack(); Getter = Expression.Lambda>(Expression.Field(instanceExpression,fieldInfo)).Comstack(); } } public void Set(T value) => Setter(value); public T Get() => Getter(); }
Et l’utiliser comme:
var accessor = new Accessor(() => myClient.WorkPhone); accessor.Set("12345"); Assert.Equal(accessor.Get(), "12345");
Une autre astuce non encore mentionnée est d’avoir la classe qui implémente une propriété (par exemple Foo
de type Bar
) définissant également un délégué delegate void ActByRef
et implémenter une méthode ActOnFoo
(et éventuellement des versions pour deux et trois “parameters supplémentaires” également) qui passeront sa représentation interne de Foo
au procédure fournie en tant que paramètre ref
. Cela a quelques gros avantages par rapport aux autres méthodes de travail avec la propriété:
Faire passer les choses est un excellent modèle; dommage qu’il ne soit plus utilisé.
Ceci est couvert dans la section 7.4.1 de la spécification du langage C #. Seule une référence de variable peut être transmise en tant que paramètre ref ou out dans une liste d’arguments. Une propriété ne peut pas être considérée comme une référence de variable et ne peut donc pas être utilisée.
Ce n’est pas possible. Tu pourrais dire
Client.WorkPhone = GetSsortingng(inputSsortingng, Client.WorkPhone);
où WorkPhone
est une propriété de ssortingng
WorkPhone
écriture et la définition de GetSsortingng
est modifiée en
private ssortingng GetSsortingng(ssortingng input, ssortingng current) { if (!ssortingng.IsNullOrEmpty(input)) { return input; } return current; }
Cela aura la même sémantique que vous semblez essayer.
Ce n’est pas possible car une propriété est vraiment une paire de méthodes déguisées. Chaque propriété met à disposition des getters et des setters accessibles via une syntaxe de type champ. Lorsque vous tentez d’appeler GetSsortingng
comme vous l’avez proposé, ce que vous transmettez est une valeur et non une variable. La valeur que vous transmettez est celle renvoyée par getter get_WorkPhone
.
Juste une petite extension de la solution Linq Expression de Nathan . Utilisez plusieurs parameters génériques pour que la propriété ne soit pas limitée à la chaîne.
void GetSsortingng(ssortingng input, TClass outObj, Expression> outExpr) { if (!ssortingng.IsNullOrEmpty(input)) { var expr = (MemberExpression) outExpr.Body; var prop = (PropertyInfo) expr.Member; if (!prop.GetValue(outObj).Equals(input)) { prop.SetValue(outObj, input, null); } } }
Ce que vous pouvez essayer de faire est de créer un object pour contenir la valeur de la propriété. De cette façon, vous pourriez passer l’object et toujours avoir access à la propriété à l’intérieur.
Si vous voulez obtenir et définir la propriété à la fois, vous pouvez l’utiliser dans C # 7:
GetSsortingng( inputSsortingng, (() => client.WorkPhone, x => client.WorkPhone = x)) void GetSsortingng(ssortingng inValue, (Func get, Action set) outValue) { if (!ssortingng.IsNullOrEmpty(outValue)) { outValue.set(inValue); } }
Vous ne pouvez pas ref
une propriété, mais si vos fonctions nécessitent à la fois get
access get
et set
vous pouvez faire circuler une instance d’une classe avec une propriété définie:
public class Property { public delegate T Get(); public delegate void Set(T value); private Get get; private Set set; public T Value { get { return get(); } set { set(value); } } public Property(Get get, Set set) { this.get = get; this.set = set; } }
Exemple:
class Client { private ssortingng workPhone; // this could still be a public property if desired public readonly Property WorkPhone; // this could be created outside Client if using a regular public property public int AreaCode { get; set; } public Client() { WorkPhone = new Property ( delegate () { return workPhone; }, delegate (ssortingng value) { workPhone = value; }); } } class Usage { public void PrependAreaCode(Property phone, int areaCode) { phone.Value = areaCode.ToSsortingng() + "-" + phone.Value; } public void PrepareClientInfo(Client client) { PrependAreaCode(client.WorkPhone, client.AreaCode); } }