|
Understandable. I can't stand code reviews myself, because I have some different philosophies about how code needs to be written than a lot of people I have worked with.
However, when I am in a position where I am in charge of code reviews, I tend to go easy and stick to enforcing in-shop style guidelines more than anything.
I don't care about fast for bizdev unless something is slow enough you want to get out and push. I would have accepted either version of your code.
I think both are readable *enough* - and this is one of the areas where I differ with a lot of people. I don't spend as much time chasing readability as other coders. I like to look at cognitive load more than readability, because I feel like readability can be had by reading the complicated parts of a function more than once. The trick is in *understanding* what you've read. That's the part where I care, but also the part I'm not great at. One of the reasons I write here is to try to improve my skillset in terms of making my code understandable. My functions are too long, but that's due to some cognitive issues I have myself, and it's part of how I've adapted to them.
Real programmers use butterflies
|
|
|
|
|
Storing the value of the property (SelectedObject ) into a local variable (objects ) is like a snapshot.
It ensures that any subsequent instruction refers to the same object.
This is important when you need consistency throughout the method, the method can be relatively time consuming and some other thread can concurrently change the property value.
You can always rely on compiler optimizations and hope that the compiled machine code will take care of such thing, or you can do it by yourself with the local variable.
Another reason could be that you know in advance that someone will add code inside the method to purposely change the object value; such change will require to put the object into a variable, like the collegue told you to do.
Doing it later will require to replace any reference to the property with references to the variable: those changes would be spread along the method polluting versioning differences.
It can even be of help if copy-paste is performed to some other method where the logic must be kept but the property to process has a different name.
These are indeed pre-optimizations, and we can argue about their usefullness and their development cost.
Additionally, the name of the property is not totally meaningful, due to the fact it is singular but it can store multiple objects (like the name of the variable unfolds): this could be an important hint for the future-you maintaining the code.
|
|
|
|
|
Just for giggles, how about:
private IMultipleComponentHandler SelectionHandler => m_selectionHandler ??= SelectedObject switch
{
null => new InspectorMultipleComponentHandler(Array.Empty<object>()),
IMultipleComponentHandler handler => handler,
object[] e when !e.GetAttributes<IgnoreIEnumerableAttribute>.Any() => e,
IEnumerable e when !e.GetAttributes<IgnoreIEnumerableAttribute>.Any() => e.Cast<object>().ToArray(),
var e => new InspectorMultipleComponentHandler(new[] { e }),
}; As with your first example, this only accesses SelectedObject once.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
we're still stuck on .NET 4.7.2 at the moment....
not for long I heard .NET 6 is coming, like the winter!
|
|
|
|
|
If you're using VS2019 or 2022, you can still use that construct in .NET 4.7.2; you just need to manually edit your project file to enable C# 9.
If you already have a <LangVersion> element in the file, change it to <LangVersion>9.0</LangVersion> . Otherwise, add that element next to the <TargetFramework> element.
Quite a few C# 8/9/10 features will work in .NET Framework projects:
Using C# 9 outside .NET 5 · Discussion #47701 · dotnet/roslyn · GitHub[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Interesting...
Though in our case there is some sort of build system, which is still mysterious to me, that generate the .csproj files.. so I would need to get familiar with that first!
In fact... I really ought to become more familiar with this particular system....
|
|
|
|
|
Whiskey. Tango. Foxtrot.
Freedom is the freedom to say that two plus two make four. If that is granted, all else follows.
-- 6079 Smith W.
|
|
|
|
|
|
Are we coding in C# or Perl? I always felt like C# was a nice balance between COBOL and Perl. But the recent changes have it trending towards Perl. I hear the excuse "it saves typing" as if we aren't on a message board or slack typing all day long.
Hogan
|
|
|
|
|
I'd use the first version - that way if SelectedObject is changed (by another thread for example) the non-null value is preserved and the app doesn't crash.
It's the way I handle event raising - my standard template code is:
public event EventHandler Name;
protected virtual void OnName(EventArgs e)
{
EventHandler eh = Name;
if (eh != null)
{
eh(this, e);
}
}
That way, in the (unlikely) event that the last handler is removed from the c=hain, the app doesn't crash and does something sensible.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Two obvious alternatives to that:
public event EventHandler Name = delegate { };
protected virtual void OnName(EventArgs e)
{
Name(this, e);
}
public event EventHandler Name;
protected virtual void OnName(EventArgs e)
{
Name?.Invoke(this, e);
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
The first relies on the empty delegate: if someone else sees the code and removes it as it clearly does nothing then you are back to a potential failure. Unlikely, yes - but I don't like app failures.
The second is .NET version dependant: the null conditional operator was introduced at C# 6, and some of my code predates that.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Very good good code review result. Absolutely meaningless and harmless change. You and code reviewer, and of course, managers, are happy.
BTW, after native optimizations both versions may be absolutely identical. But don't tell about this to your manager.
|
|
|
|
|
It’s unlikely the compiler knows that no other thread may change the SelectedObject during the getter body. One should acknowledge that fact by capturing its value, not for speed or readability, but for correctness.
That so many people find it trivial or overly optimizing is really scary. Pragmatically it may be a non-issue, but it’s a time-bomb and there’s arguably no justification for the “simpler” syntax. Concurrency is hard.
|
|
|
|
|
I have problems with both.
"var" is a coding shortcut when you're too lazy to type, and should be replaced with the actual type when it resolves (before release); so the next guy doesn't have to "intelli-sense" it. "Object" seems more appropriate in this case.
I dislike "long" if's and would have "if not null return x" instead of (if null etc.)
Even though it works, I don't declare properties "after" the method that references them.
The return "assign" is "different".
Then there are the if's with bracketed blocks and some without. Saving keystrokes?
etc.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|
You’re not wrong, but you’re also not necessarily right. Coding preferences should be agreed upon, codified, and automated to avoid debate. The important thing is that there’s consistency.
Calling a coding practice “lazy” (like the use of ‘var’) is condescending, at best, and smells of arrogance. It’s also associated with narrow-mindedness, and quite frankly, can date you in a bad way. I’m sure the intent was a call for action, but your reasoning and diction could be improved.
Very simply, the guidance on the use of ‘var’ states that it should be used only if the type is repeated or obvious (without IntelliSense) on the right side of the equals sign; this simultaneously makes it easier to spot variable declarations while respecting the intelligence of the reader, who may not really care what the type is up front, especially if the name is well-chosen or the type name is long. A similar logic can be applied, per your preference, for the implicit new() operator, though I tend to see those used mostly on field initializers. Having said that, the Framework Design Guidelines recommends *against* the use of var, except when using ‘new’, ‘as’, or a hard cast, in which cases it is *permissible*.
|
|
|
|
|
I would have done things this way:
private IMultipleComponentHandler SelectionHandler
{
get
{
if (m_selectionHandler == null)
{
if (SelectedObject is IMultipleComponentHandler handler)
{
m_selectionHandler = handler;
}
else
{
object[] collection;
if (SelectedObject is IEnumerable e
&& !SelectedObject.GetAttributes<IgnoreIEnumerableAttribute>().Any())
{
collection = e as object[] ?? e.Cast<object>().ToArray();
}
else if (SelectedObject != null)
{
collection = new[] { SelectedObject };
}
else
{
collection = Array.Empty<object>();
}
m_selectionHandler = new InspectorMultipleComponentHandler(collection);
}
}
return m_selectionHandler;
}
}
private IMultipleComponentHandler m_selectionHandler; I'm an old fart who prefers single-exit .
Software Zen: delete this;
|
|
|
|
|
I would be tempted to extract the contents of the if statement as a function, like this:
public IMultipleComponentHandler SelectionHandler
{
get
{
if (m_selectionHandler == null)
{
m_selectionHandler = InitialiseSelectionHandler(SelectedObject);
}
return m_selectionHandler;
}
}
private IMultipleComponentHandler InitialiseSelectionHandler(object selectedObject)
{
if (selectedObject is IMultipleComponentHandler handler)
return m_selectionHandler = handler;
object[] collection;
if (selectedObject is IEnumerable e
&& !selectedObject.GetAttributes<IgnoreIEnumerableAttribute>().Any())
{
collection = e as object[] ?? e.Cast<object>().ToArray();
}
else if (selectedObject != null)
{
collection = new[] { selectedObject };
}
else
{
collection = Array.Empty<object>();
}
return new InspectorMultipleComponentHandler(collection);
}
private IMultipleComponentHandler m_selectionHandler;
This hides the issue of using a temporary variable, snapshots the SelectedObject so the value being used can not change while updating the handler and the getter property for SelectionHandler becomes easier to read.
An added bonus is if SelectedObject changes you can update the handler by calling InitialiseSelectionHandler.
|
|
|
|
|
This is way cleaner..
It is a sort of lazy initialization.. and usually it is split exactly that way: a backing field, a property that lazily initializes the field, and a method that performs the initialization.
This also highlight a possible race condition after the very first null check, that can be avoided by a double-checked locking inside the property get accessor; and the InitialiseSelectionHandler method would remain untouched.
I'd just keep the backing field close to the property (I usually keep the field immediately before the property).
|
|
|
|
|
|
I was struck by a quote from an Insider News article Kent posted about some new DevOps developments: [^]:
"The cusp of maturation of previously bleeding-edge paradigms."
My head went fast-forward to 2025, where a developer named Devindra Codearaja has just received a reply/warning from his Dev-Ops team's "Substance Enhancement" committee ... I quote:Quote: Dear Valued Team Member, Devindra,
We have evaluated your request to increase your daily methamphetamines allowance, and, given the results of your most recent blood-screening profile, we must say, in the interests of the Team, we cannot grant that request.
We have detected trace amounts of MDMA aka "Ecstasy" [^] in your blood; as you know, MDMA is not an approved substance for your Team.
It is in the interests of the Team to avoid excessive empathy, and distracting personal insights, or inappropriate bonding behavior: all of which are associated with this drug.
Since your work is excellent, and your behavior in SCRUM slug-fests is appropriate, we will take no punitive action at this time.
However, per your contract, your supplementation will be modified to include:
1) daily: 5 mg. of Xanax given orally
2) 1x weekly: LSD 25 micro-grams to be given orally 2hrs. before Friday SCRUM.
Do be aware that if the next screening shows any signs of unauthorized drugs ... or indicates you have not taken your approved supplements ... further action may be required.
Please schedule a private session with our substance-counsellor bot.
Sincerely, Edwina Hawkins,
Substance Enhancement Committee
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
Or maybe I'm just getting paranoid.
singing
Liars, Vipers, Jokers and Fakes: we have a man in a room with a photograph of you and a very long list
we really get around everybody is written down, nobody ever gets missed
we know you through and through - know more about you than you know about yourself
we got a magical machine that has every word you speak and can write it all down
so you better watch your mouth or we'll come knock on your door.
we are the liars and vipers and jokers and fakes everywhere you go
the liars and vipers and jokers and fakes on your radio
we are the liars and vipers and jokers and fakes in the driver's seat
we are the liars and vipers and the clowns at the wheels of history
WHITEY - LIARS, VIPERS, JOKERS & FAKES (OFFICIAL AUDIO) - YouTube[^]
I'm not sure if how I feel is because of the encroaching surveillance state coming to us live by way of well... you and me when it comes down to it, or whether it's because of the general political landscape in the west, or what. This song gets to me.
Real programmers use butterflies
|
|
|
|
|
|
YIKES!
Nickelback was a psyop campaign by Canada intended to weaken the US, and they should face sanctions over it.
Real programmers use butterflies
|
|
|
|
|
Don't worry, the reptilian underground overlords are onto it!
|
|
|
|
|