Changing object properties from method (Best Practise) - c#

I have a question for you. What is best practise to change object properties in method. Let's assume that I have a method like this:
public void ChangeThis(MyObj myobj)
{
myobj.Prop = 5;
}
Isn't better to return that object like we want to show that we change something?
public MyObj ChangeThis(MyObj myobj)
{
myobj.Prop = 5;
return myobj;
}
What is best practise to change object properties from methods?

The second method is bad as it is ambiguous as to whether a new instance of the object is created with the changed property or if the current instance is returned.
I would only use the second method if my objects were immutable.
The name of the method, ChangeThis, implies that the object is mutable, but by returning an object it suggests that they are not.

It depends.
While the first case appears more often, the second one is a useful, when you want to combine method calls in chain:
myObject
.ChangeThis()
.ChangeThat()
.ChangeSomethingElse();
I think, StringBuilder is a very good example:
sb
.AppendLine("1")
.AppendChar('2')
.AppendLine()
.ToSting();
The same API have model configuration classes from Entity Framework:
Property(_ => _.Name)
.HasColumnName("name")
.HasMaxLength(64)
.IsRequired();
Thus, sometimes this is very convenient way to call methods.
Imagine, how the code from above would look in 1st case:
sb.AppendLine("1");
sb.AppendChar('2');
sb.AppendLine();
sb.ToSting();
Sadly, isn't it?

If you want to make it obvious that the internal state of the object was changed, do it so by choosing a proper name for the method, and by adding proper XML documentation.
I don't think this is a good enough reason to return the object back to the client and, quite honestly, it's confusing. Are you returning a new object? Or is it the same object that was passed as a parameter? However, if the type is immutable, then you should return it.

Related

Create an instance of the DeclaringType of a method: Activator.CreateInstance

I once again am struggling with reflection. I just give you the piece of code that my debugger does not bite:
public bool HandleCommand(string command)
{
MethodInfo m = methods.FirstOrDefault(t => t.GetCustomAttribute<CommandAttribute>().Name == command);
ICommandSet set =(m.DeclaringType)Activator.CreateInstance(m.DeclaringType);
m?.Invoke(set, null);
return true;
}
Basically, this code is inside a class called CommandHandler. When it's constructed, it loops over all the types in the executing assembly that implement a certain interface, and store all their methods that have a CustomAttribute attached to it in List; For this question's purpose I just assume that everything is working there. The attribute has just one property:
[AttributeUsage(AttributeTargets.Method)]
public class CommandAttribute : Attribute
{
public string Name { get; set; }
public CommandAttribute(string name)
{
Name = name;
}
}
Now in the method you saw above, the HandleCommand() method, I store the method which's name property is equal to the string I passed in in a MethodInfo m. Now my question essentially is, how I properly Invoke this method. m.Invoke needs an object that calls it, and because passing in "this" does not work, and examples online always passed in an instance of the class it was defined in, I figured I needed to create an instance of the class m was defined in and just pass this into the Invoke() method. In practice, this is a lot harder than I thought, and my best guess is what you can see above, with the activator.
ICommandSet set =(m.DeclaringType)Activator.CreateInstance(m.DeclaringType);
First of all, I know for sure that the class that m is declared in implements ICommandSet, because this is a creterium for a type to be inspected for the methods. So this is why I say "ICommandSet set". Then the Activator shall create this instance. But it does not work. The only error message provided states that m is a variable but is used like a type. However, when I pass it in as a param to Activator.CreateInstance() the compiler seems to dig it just fine. I absolutely don't know how I might fix this problem, as I don't really understand what is the problem. Is there anyone out there who can help me?
Also, all the methods are defined in different classes and even projects, so I don't know which class the methods are defined in.
The reason you're receiving this is your syntax is wrong. You cannot perform a cast with a variable dereference as the desire type. As you already know you wish to treat "set" as an "ICommandSet" cast to that instead.
var set = (ICommandSet) Activator.CreateInstance(m.DeclaringType);
You can also do it safe
var set = Activator.CreateInstance(m.DeclaringType) as ICommandSet;

Delegating access to a class property instead of an object property

I've been trying to figure out a way to deal with property mapping and naming programmatically. The thing is that I don't want to have to change multiple portions of code to be able to extend the map. The code I have right now is like this:
public static class Names
{
public const string Property = "propertyNameToBeUsedInJson";
}
...
switch(propertyName)
{
case Property:
user.propertyToBeMapped = json.propertyValue;
break;
}
What I really wanted was to be able to have some sort of dictionary where I could do something like:
Dictionary<string, Action>() { {"propertyNameToBeUsedInJson", <Class of User>.propertyToBeMapped} };
That means I would be delegating access to a property of a Class, not to a concrete object. This way I can iterate over this dictionary and if it contains the key I'm looking for, then I just go and change the property pointed by the value.
I think that a overhead during initialization is ok, but I don't want to use Reflection on a per call basis.
The questions is: Is it possible to use the second way having in mind the statement above? If so, how should I go for it?
Just to summarize the comments:
It is definitely possible to do it with a dictionary, but properties cannot be used quite this way. Remember that properties are just syntactic sugar so you don't have to write get/set methods yourself. The best way to get it into a dictionary is probably by wrapping it into a delegate:
new Dictionary<string, Func<YourClass, string>>()
{
{"propertyNameToBeUsedInJson",
instance => instance.YourProperty}
};
Then, you would use it very easily like this (error checking omitted):
user.propertyToBeMapped = dictionary[propertyName](yourClassInstance);
This will only work if the instance is always the same class. If not, the first parameter of the Func would have to be some base class (maybe even object) and then the delegate would have to do some type-checking and conversion.

static in interfaces

i want to write my own serialisation (xml and binary do not fit for me,
i want "a more ADO" way)
so i defined an interface:
interface ISerializeData
{
DataTable GetDataSchema();
DataTable SerializeData();
object DeserializeData(DataTable data);
}
now i do not want to create an instance of an object to let
me get the schema for that object.
And: DeserializeData should return an instance, not use an instance.
Therefore i think it should be also static. (okay, it can initialize
an instancce from a datatable...)
Any ideas? How can i model that? static is not allowed in
interfaces and my classes already inherit from another abstract
base class.
Any ideas appreciated!
that issue is why the other serializer utilize attributes as they allow you to provide metadata about how the class is to be stored with out forcing you to deal with the implementation of the class itself.
Maybe I'm wrong, but this is really more a task for a utility class. Take DeserializeData, for instance. Somewhere in your code you decide which type you're going to construct. In your proposed code you would choose the type and call its static method. Now what? Would each type have its own code to do the serialization? You'd probably end up creating some class doing all the work, to stay DRY. So you might as well have one DeserializeData method in a utility class, like:
public static T DeserializeData(DataTable data)
where T : new
{
var T = new T();
.... // Set properties
}
In this method you'd probably get the data schema.
Maybe SerializeData() could be an instance method, but that too would delegate its work to some utilty class.
Please let me know if I completely misunderstood your question.

Possible to create a new instance of a type without reflection?

I have a function that at the moment takes a Type variable. This function sticks it in a list and such and eventually needs will create a class of that type.
Right now I do that with
object o=MyType.GetConstructors()[0].Invoke(new object[0]);
which is pretty hacky and also will not work in medium trust due to reflection(I think). Is there a better way of doing this without reflection?
The Type is defined this way as part of a function. I need the class to be created "lazily" because it may not be created in the application if it's not needed. I use it for example like
AddToList(typeof(Whatever));
Note, I'm open to suggestions on changing the function calling. I just need the object to be created lazily and for to store the type(or however to create an object of the type) in a list.
I've considered lambdas but I'm not sure they'd work here.
Using Generics:
public void Method<T>() where T : class, new()
{
//code
T t = new T();
}
Using Activator (still reflection, meh):
object t = Activator.CreateInstance(yourTypeVariable);
Personally, I would prefer the first solution due to being strongly typed. However, you should be aware that both methods only allow for parameterless constructors. If you need to pass parameters, you will need reflection or expression trees.
Another alternative solution is FormatterServices.
object instance = FormatterServices.GetUninitializedObject(typeof(MyClass));
Note that the instance is created without any fields/properties initialized, even you have
class MyClass
{
public int i = 99;
public Object o = new object();
}
instance.i will be 0 and instance.o will be null. It's quite hard to provide a pure non-reflection solution(because always you need to call o.GetType()). This solution essentially serialize the object and then deserialize it to an object, so you don't need to use reflection to call its constructor. But there is still reflection when serialization/deserialization.
After further research on lambdas, I've discovered they will give me a much more elegant solution and it does not use reflection
So I used in my list definition
public delegate MyBaseType TypeCreator();
...
public TypeCreator Creator;
and in my function call, a simple and elegant lambda:
AddToList(()=>{return new MyType();});
I think this is quite a bit cleaner than my reflection method because it allows putting parameters into the constructor, and a few other reasons outside of the scope of this question. (It just goes with my project well)

Using type object as returning type - bad practice?

I have a method
private object SetGrid(IGrid grid)
{
grid.PagerHelper.SetPage(1, 10);
grid.SortHelper.SetSort(SortOperator.Ascending);
grid.PagerHelper.RecordsPerPage = 10;
return grid;
}
which returns an object of type object.
Then I cast the object back to the previous type.
var projectModel = new ProjectModel();
projektyModel = (ProjectModel)SetGrid(projectModel);
The gain of this is, the method SetGrid can be reused across the app.
Is this a common practice or should I avoid doing this ?
You could use a generic method instead, and constrain the type argument to your IGrid interface:
private T SetGrid<T>(T grid) where T : IGrid
{
grid.PagerHelper.SetPage(1, 10);
grid.SortHelper.SetSort(SortOperator.Ascending);
grid.PagerHelper.RecordsPerPage = 10;
return grid;
}
You should still be able to call the method in exactly the same way, just without the cast. Type inferencing should be capable of automagically figuring out the required generic type argument for you:
var projectModel = new ProjectModel();
projektyModel = SetGrid(projectModel);
EDIT...
As other answers have mentioned, if your IGrid objects are reference types then you don't actually need to return anything at all from your method. If you pass a reference type then your method will update the original object, not a copy of it:
var projectModel = new ProjectModel(); // assume that ProjectModel is a ref type
projektyModel = SetGrid(projectModel);
bool sameObject = object.ReferenceEquals(projectModel, projektyModel); // true
Since you are passing in an object of a class that implements IGrid you could just as well change the return type to IGrid.
Also, since it's a reference type you don't even need to return the grid again. You could just as well use this:
var projectModel = new ProjectModel();
SetGrid(projectModel);
This is better accomplished with generics. You can use a constraint on the generic typeparam to preserve your type safety!
private T SetGrid<T>(T grid) where T : IGrid
{
grid.PagerHelper.SetPage(1, 10);
grid.SortHelper.SetSort(SortOperator.Ascending);
grid.PagerHelper.RecordsPerPage = 10;
return grid;
}
and then
var projectModel = new ProjectModel();
projectModel = SetGrid(projectModel);
Here, the generic typeparam "T" is actually inferred by the compiler by the way you call the method.
It's worth noting that in the particular use-case you've demonstrated, returning grid is probably unnecessary, as your original variable reference will be appropriately modified after the method call.
In the case you illustrate above there is no need to return grid. The IGrid instance is passed by reference, so your projectModel reference will be updated with the changes you've made in the SetGrid method.
If you still want to return the argument, at least return IGrid, since it is already known that the argument is an IGrid.
In general, provide as much type information as you can when programming in a statically typed language/manner.
"Is this a common practice or should I avoid doing this ?"
This is not common practice. You should avoid doing this.
Functions that only modify the parameter passed in should not have return types. If causes a bit of confusion. In the current C# you could make the modifying function an extention method for better read-ability.
It causes an unnecisary cast of the return type. It's a performance decrease, which may not be noticable... but its still needless since you are casting from an interface, return that interface even if the object is different from the parameter passed in.
Returning object is confusing to users of the function. Lets say the function created a copy and returned a copy... you would still want to return the interface passed in so that people using the function know "hey i'm getting an IGrid back." instead of having to figure out what type is being returned on thier own. The less you make your team mates think about stuff like this the better, for you and them.
This is a very weird example because SetGrid doesn't seem to do a lot of things other than setting some defaults. You are also letting the code perform manipulation on the object that could very well do that by itself. Meaning IGrid and ProjectModel could be refactored to this:
public interface IGrid {
// ...
public void setDefaults();
// ...
}
public class ProjectModel : IGrid {
// ...
public void setDefaults() {
PagerHelper.SetPage(1, 10);
SortHelper.SetSort(SortOperator.Ascending);
PagerHelper.RecordsPerPage = 10;
}
// ...
}
Using this refactoring you only need perform the same with this:
myProjectModel.setDefaults();
You could also create an abstract base class that implements IGrid that implements the setDefaults() method and let ProjectModel extend the abstract class.
what about the SOLID principles ? Concretely the Single Responsibility Principle. The class is in the first place something like a DTO. – user137348
I'm exercising the Interface Segregation Principle out of the SOLID principles here, to hide the implementation from the client of the class. I.e. so the client doesn't have to access the internals of the class it is using or else it is a violation of Principle of Least Knowledge.
Single Responsibility Principle (SRP) only tells that a class should only have one reason to change which is a very vague restriction since a change can be as narrow and broad as you want it to be.
I believe it is okay to put some configuration logic in a parameter class if it is small enough. Otherwise I'd put it all in a factory class. The reason I suggest this solution is because IGrid seems to have reference to PagerHelper and SortHelper that seem to be mutators for IGrid.
So I find it odd that you mention the class being a DTO. A DTO from a purist sense shouldn't have logic in it other than accessors (i.e. getter methods) which makes it strange that ProjectModel itself has references to PagerHelper and SortHelper which I assume can mutate it (i.e. they're setters). If you really want SRP the "helpers" should be in a factory class that creates the IGrid/ProjectModel instance.
Your grid is an IGrid, why not return IGrid?

Categories