|
Looks like it's trying to compete with compiler error messages involving C++ templates.
|
|
|
|
|
There are so many things not to like about C++ templates but I love them anyway. It's shameful, my inconsistencies in this regard. I suppose it's because LINQ wasn't part of C# since the beginning, I didn't consider C# and LINQ to be irrevocably linked (pardon the pun) the way I do with C++ and templates. It's part of the language, not a "bag on the side". That probably contributes to the difference in attitude I have toward each. But also a little inconsistency never really bothered me that much.
Real programmers use butterflies
|
|
|
|
|
honey the codewitch wrote: But also a little inconsistency never really bothered me that much.
A foolish consistency is the hobgoblin of small minds.
-- Emerson
Freedom is the freedom to say that two plus two make four. If that is granted, all else follows.
-- 6079 Smith W.
|
|
|
|
|
Reminds me of people who don't use paragraphs.
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
|
|
|
|
|
My crystal ball says your object's type doesn't contain any generic arguments, so you're passing null to AddRange .
var genericArguments = obj.GetType().GetGenericArguments();
if (genericArguments.Length != 0)
{
Columns.AddRange(genericArguments[0].GetProperties()
.Where(p => p.GetCustomAttributes(true).OfType<BrowsableAttribute>().FirstOrDefault()?.Browsable ?? DefaultBrowsableState)
.Select(p => new ColumnHeader
{
Name = p.Name,
Text = p.GetCustomAttributes(true).OfType<DisplayNameAttribute>().FirstOrDefault()?.DisplayName ?? p.Name,
});
} Throw in a custom extension method to simplify it slightly:
public static class AttributeExtensions
{
public static TAttribute GetCustomAttribute<TAttribute>(this ICustomAttributeProvider value, bool inherit = true)
where TAttribute : Attribute
{
if (value is null) throw new ArgumentNullException(nameof(value));
object[] attributes = value.GetCustomAttributes(typeof(TAttribute), inherit);
return attributes.Length == 0 ? null : (TAttribute)attributes[0];
}
}
var genericArguments = obj.GetType().GetGenericArguments();
if (genericArguments.Length != 0)
{
Columns.AddRange(genericArguments[0].GetProperties()
.Where(p => p.GetCustomAttribute<BrowsableAttribute>()?.Browsable ?? DefaultBrowsableState)
.Select(p => new ColumnHeader
{
Name = p.Name,
Text = p.GetCustomAttribute<DisplayNameAttribute>()?.DisplayName ?? p.Name,
});
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Yeah I sorted it out. It was being applied to an instance of the wrong class. The code that's using it is ridiculously complicated, and something small was out of place.
This error was the end result. I still think it's suitable for the purposes of this rant.
Such is life sometimes. I'm working with lots of Other People's Code(TM) at the moment. It's not so much that any one of them is particularly bad, so much as gluing together so many different paradigms is well.. as you can expect. But the main complication of it all is making it designable so my client can open it up in visual studio and tweak it, because he likes to be able to. He can code some, but I'd prefer he keep his mitts off what i write. I can deal with him using the designer. It works for both of us because he's afraid of my code anyway, and that way he doesn't have to bug me for little changes, but sometimes the code to make it all go properly is nasty.
Real programmers use butterflies
|
|
|
|
|
All this complaining about LINQ and AddRange, a non-LINQ function, was the problem?
Nothing a good old stack trace couldn't have pointed out by the way
|
|
|
|
|
Which functions takes a "values" parameter? I would guess it's Columns.AddRange() ?
If so, then my first guess would be that the problem is with obj.GetType().GetGenericArguments() not having any items (length == 0).
I guess this is one of the reasons we try to write readable code... so we also get more specific error messages. This one-liner nonsense is bad for everyone.
|
|
|
|
|
The underlying issue is that this garbage is a "one-liner". One-liners are darn near impossible to debug. LinQ invites, and even encourages this crap into the code.
|
|
|
|
|
As does SQL. If a given statement works, just keep piling on until it doesn't, then post it in Q&A.
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
|
|
|
|
|
And Linq combined with extension methods makes one-liners even more fun! I write them frequently!
|
|
|
|
|
I find that adding line breaks makes it a lot easier to read. Remember, you are writing for the next person to touch the code, not the computer. It is missing some Elvis operators, before the Where, the Select, and the ToArray, along with providing a value if the null propagates to the end.
Also, you don't need the ToArray() as AddRange takes an IEnumerable<T>.
Columns
.AddRange(
obj.GetType()
.GetGenericArguments()
.FirstOrDefault()?.GetProperties()
?.Where(p =>
{
return p.GetCustomAttributes(true)
.OfType<BrowsableAttribute>()
.FirstOrDefault()?.Browsable ?? DefaultBrowsableState;
})
?.Select(p =>
{
return new ColumnHeader()
{
Name = p.Name,
Text = p.GetCustomAttributes(true)
.OfType<DisplayNameAttribute>().FirstOrDefault()?.DisplayName ?? p.Name
};
})
?? Array.Empty<ColumnHeader>()
);
"Time flies like an arrow. Fruit flies like a banana."
|
|
|
|
|
In my defense I didn't write that, nor run it through autoformat yet.
Real programmers use butterflies
|
|
|
|
|
Matthew Dennis wrote: I find that adding line breaks makes it a lot easier to read
|
|
|
|
|
Matthew Dennis wrote: It is missing some Elvis operators
It's not. If the FirstOrDefault returns null , the GetProperties and subsequent calls won't execute. If it returns non-null, GetProperties will never return null :
Returns
An array of PropertyInfo objects representing all public properties of the current Type.
-or-
An empty array of type PropertyInfo , if the current Type does not have public properties.
Similarly, Where will never return null . If the input sequence is null , it will throw an exception. If the input sequence is empty, or there are no matching elements, it will return an empty sequence.
And the same applies to Select - it will either throw an exception, or return a non-null sequence.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
actually that is incorrect. Only the chain of conditional operators is short circuited so if you have the expression
A()?.Bb()?.C().D()
and A() returns null the B and C will not be executed but there will be an attempt to execute D on a null object.
Its sort of like async. You need to go all the way down.
[Member access operators and expressions - C# reference | Microsoft Docs](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-)
"Time flies like an arrow. Fruit flies like a banana."
|
|
|
|
|
I'm not convinced.
static Foo A() => null;
public class Foo
{
public Foo B() => null;
public Foo C() => null;
public Foo D() => null;
}
...
Foo result = A()?.B().C().D(); Null conditional operator | C# Online Compiler | .NET Fiddle[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
You may be correct. The documentation is a little vague on the extent of the short circuiting.
"Time flies like an arrow. Fruit flies like a banana."
|
|
|
|
|
I checked this out and it appears that as long as the null occurs before a ?. or ?[] operator, the rest of the chain is short circuited and has a value of NULL.
You learn something everyday.
Thanks
"Time flies like an arrow. Fruit flies like a banana."
|
|
|
|
|
I'm not an expert or even a novice ...
(serious)
Can't you just "unLINQ" this and find and fix the error and LINQ it up again ?
I'd rather be phishing!
|
|
|
|
|
Yes. But that's my point. To get a reasonable error message out of LINQ the solution is do it without LINQ. meh.
Real programmers use butterflies
|
|
|
|
|
It's not really LINQ's fault, it's the chaining of multiple commands into a single statement and also a little of your own inexperience; given that error message many would know exactly where to look.
|
|
|
|
|
A couple of possibly interesting bits of feedback, assuming that code comes from here:
- Adding it to a WinForms app created with .NET Core 3.1 or .NET 5 and turning on nullable reference types finds 17 potential accidental nulls in the code from that SO post. But the Columns.AddRange call itself isn't one of them because WinForms wasn't built with NRT enabled. So the compiler decides it can't say one way or another if passing a null values argument to AddRange is okay.
- Resharper catches the potential error whether you're using .NET Core/.NET 5 or .NET Framework. It even suggests a fix. The static analysis it's doing must look at AddRange and notice that the first thing that method does is throw an exception if values is null.
|
|
|
|
|
Ryan Peden wrote: Resharper catches the potential error
Ryan Peden wrote: It even suggests a fix.
|
|
|
|
|
Sounds like nullable reference types is reason enough in itself to upgrade to .Net 5.
|
|
|
|