Vorrei poter copiare un oggetto e modificare solo alcuni valori. Ho trovato due modi diversi per farlo.
// OPTION A - create a copy constructor and use property
// initialization to change values
class SomeObject {
public string PropertyA { get;set; }
public string PropertyB { get;set; }
public SomeObject() { }
public SomeObject(SomeObject copyFrom) {
PropertyA = copyFrom.PropertyA;
PropertyB = copyFrom.PropertyB;
}
}
var original = new SomeObject() {
PropertyA = "original value",
PropertyB = "some other original value",
}
// replace only the values I want to replace
var partialCopy = new SomeObject(original) {
PropertyA = "some new value different from original",
};
// OPTION B - create an Option<T> type and use that
// used as constructor paramaters
public class Option<T> {
// used in the case where you want
// the default value of a type instead
// of the original value (see usage below)
public static readonly Default = new Option<T>(default(T));
public T Value { get; private set; }
public Option(T value) {
Value = value;
}
public static implicit operator T(Option<T> o) {
return o.Value;
}
public static implicit operator Option<T>(T value) {
return new Option<T>(value);
}
}
public class SomeObject {
public string PropertyA { get; set; }
public string PropertyB { get; set; }
public SomeObject() { }
public SomeObject(SomeObject toCopy,
Option<string> propertyA = null,
Option<string> propertyB = null)
{
PropertyA = propertyA ?? toCopy.PropertyA;
PropertyB = propertyB ?? toCopy.PropertyB;
}
}
var original = new SomeObject() {
PropertyA = "original value",
PropertyB = "some other original value",
};
// replace only the values I want to replace
var partialCopy = new SomeObject(original,
propertyA: "new value");
La prima implementazione ha molto meno codice da mantenere, ma non è possibile applicare le cose nel costruttore. Il secondo è un po 'più complicato a causa della classe Option<T>
ma è possibile, in effetti, applicare meglio le regole in un costruttore durante la creazione dell'oggetto. Pensi che la sicurezza del costruttore di OPTION B
prevale sulla complessità, rendendola la scelta migliore. O dovrei usare il OPTION A
più semplice a causa della facilità di manutenzione?
Questi sono oggetti di trasferimento dati semplici. In genere hanno molte proprietà. Sto cercando di evitare di creare oggetti come template, templateB, templateB.2, etc.
quando posso semplicemente copiare l'oggetto corrente e modificare le proprietà di cui ho bisogno. Ad esempio, le proprietà A, B e C devono essere impostate su questo valore quando passa una determinata regola. Tuttavia, nel processo, le proprietà D, E e F avranno bisogno di valori diversi in base ad altre regole. Sto cercando di evitare codice come il seguente:
// I'm trying to avoid this
ResponseObject SomeMethod(bool inputA, bool inputB) {
var myObject = CreateObjectFromTemplateA(); // has same values for A,B,C
if(inputA) {
myObject.D = "some value";
myObject.E = "some value";
myObject.F = "some value";
} else if (inputB) {
myObject.D = "some other value";
myObject.E = "some other value";
myObject.F = "some other value";
}
return myObject;
}
// and do something like this instead
ResponseObject SomeMethod(bool inputA, bool inputB) {
var defaultValue = CreateFromTemplateA()
return inputA ? new ResponseObject(defaultValue) { D = "some value",
E = "some value",
F = "some value",},
: inputB ? new ResponseObject(defaultValue) { D = "some other value",
E = "some other value",
F = "some other value",},
: defaultValue;
}
// in some cases it's as simple as one property change
// and here is where the first method of property initialization
// breaks down
ResponseObject SomeMethod(bool inputA, bool inputB) {
return new ResponseObject(CreateFromTemplateA()) {
D = inputA ? "some value"
: inputB ? "some other value
: CreateFromTemplateA(), // a second object created
};
}
// here is where the constructor initialization helps
ResponseObject SomeMethod(bool inputA, bool inputB) {
return new ResponseObject(CreateFromTemplateA(), // with this method CreateFromTemplateA() could be a property instead of a method call
d: inputA ? "someValue"
: inputB ? "someValue"
: null // null here indicates use the property value from CreateFromTemplateA()
);
}