What are the best practices for nested objects in .Net? [closed]
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
开发者_开发问答 Improve this questionThis question has to do with best practices... please do not confuse it with premature optimization.
I noticed in .Net that deep object referencing takes quite some time to process when compared to flat or shallow objects. For example:
object1.object2.object3.object4.Property
... is not efficient since, I conclude, each object has to be de-referenced along the path. This is in contrast to C, where Property
's memory ref would be calculated by the compiler, rather than at run time.
Now, we obviously wouldn't take all the fields of object2+ and flatten them into object1 just for speed. The coding would be unwieldy and hard to manage. But the speed difference could be significant.
So my question is, "What is the best practice in building deep objects vs. flat(ish) objects?" And, further, is there any advantage to using structs where one is simply trying to group a number of fields together, such as:
public struct SizeData
{
public long Written;
public long Read;
public int Size;
}
The two questions relate.
EDIT
To illustrate:
public class Leaf
{
public int Property;
}
public class Depth1
{
public Leaf Leaf;
}
public class Depth2
{
public Depth1 Depth1;
}
public class Depth3
{
public Depth2 Depth2;
}
private void button12_Click(object sender, EventArgs e)
{
Depth3 depth = new Depth3();
depth.Depth2 = new Depth2();
depth.Depth2.Depth1 = new Depth1();
depth.Depth2.Depth1.Leaf = new Leaf();
Leaf leaf = new Leaf();
var T1 = Environment.TickCount;
for (int i = 0; i < 100000000; i++)
{
depth.Depth2.Depth1.Leaf.Property++;
}
var T2 = Environment.TickCount;
for (int i = 0; i < 100000000; i++)
{
leaf.Property++;
}
var T3 = Environment.TickCount;
MessageBox.Show((T2 - T1).ToString() + Environment.NewLine +
((T3 - T2).ToString()));
}
The only concern here IMHO is not speed, but dependency. Have you ever tried to refactor an application that frequently uses deep object nesting like this? It's a pain in the arse. Have a look at the Law of Demeter (or as I say, the Guideline of Demeter). The idea is that instead of using
person.Address.ZipCode
you instead use something like
person.AddressZipCode
to avoid a dependency on the Address object. Is it faster? Maybe, if you implement it right. But I personally don't care because the speedup is really trivial. All I care about here is reducing dependencies.
The term nested class is usually used to mean "nested type".
class Foo
{
private class FoosHelper { .. }
}
The best practice here is to use them sparingly and prefer private.
But your example is not about nested classes but about nested objects instead:
object1.object2.object3.object4.Property
The best practice would be: build a logical and cohesive object-model first and foremost.
Your suggestion of 'flattening' seems to be about sacrificing the core architecture for a tiny optimization. Not such a good idea.
And to the (only slightly) related struct question:
is there any advantage to using structs where one is simply trying to group a number of fields together
No, usually not. There are rare case where you would need very large arrays of small types but in general using a struct brings only disadvantages.
In my opinion, you shouldn't take the speed into consideration until you realize it's a bottleneck.
The classes/structs should be grouped purely logically: if you see that some class is a part of some other class, that it is needed only inside the bigger class and makes sense only inside the bigger class, then you should put it there and thus avoid polluting namespace. If you see that your smaller class is useful outside the bigger class, define it outside. That simple.
Summing it up: put your class/structure to the deepest appropriate level, but not deeper.
Examples:
myCar.RegistrationDate.Year.IsLeap
makes perfect sense, and is much better thanmyCar.IsRegistrationYearLeap
point.Coordinates.Cartesian.X
doesn't make much sense,point.X
is much better.
Struct field will not have separate memory allocation then the enclosing object, so there is no difference how deep it is, if all of the nested are structs, it's computed by the compiler.
If you nest the reference types, they have to be dereferenced, and this is not any different from C++.
精彩评论