✅ Indexer return collection or single object depending on parameter
Hi all,
is there any way to selectively return either a single object or a collection of multiple objects depending on the given parameter?
I want to achieve the following behavior:
Let's say I have some class which references a table by Rows (alphabetically, e.g. A, B, C, ...) and Columns (numerically, e.g. 1, 2, 3, ...)
If I want to have a reference to the cell
A1
I would write the following:
Additionally, I would also like to be able to give ranges as the index. For example:
Is there any way of achieving such a behaviour?
Thank you very much for your help!20 Replies
Yes, you can create your own indexer in your class like this and create a method like "GetCell" for the logic: But for your indexer returning a collection you will need a different signature, because you can't have two indexer with the same parameter types, for example:
Yeah, I thought about doing that. That would probably work (and I considered that option, maybe should've included that), but partially just out of interest I would really like to know if it would be possible with my proposition.
Yeah, you can't return different types for same parameter types. What could work is returning a base class or an interface for both, but I don't think that would work well.
You can probably have two indexer, one of which accepting https://learn.microsoft.com/en-us/dotnet/api/system.range?view=net-7.0
Range Struct (System)
Represents a range that has start and end indexes.
Then it would also be type safe
If the first one returns a single item while the latter returns an iterable colection
If that works with your type of range of course
I'm not sure anymore but I think indexers can also accept multiple parameters, that could also work
So you can have one accepting a single string while the other takes multiple string params
Yes, that would be the solution @Sterbehilfe proposed, that would surely work.
I'll have a look into ranges. Never used them before, so I can't for sure say whether or not they work for my use case. Thanks for the suggestions, though!
Oh true I've just noticed, the second example Sterbehilfe mentioned is what I meant as well
Okay, had a quick look at
Range
. It seems like Range
s won't be the solution either. Their constructor is Range(Index, Index)
, and the Index
constructor is Index(int value, bool fromEnd = false)
, which I wouldn't be able to properly use as my data structure is more like a Dictionary
. I could, of course, introduce some sort of ordering on the Dictionary
, but the Range
"operator" (e.g. [1..3]) still isn't what I'm searching for.
Something interesting I found: The range operator is exclusive of the latter part, So [1..4] will give back the first 3 elements, which I find to be quite unintuitive.It actually gives the second - fourth elements
Programming usually has exclusive upper bounds
Random's upper bound is exclusive
Python's
range
is exclusive upper bound
This really isn't a place for indexers, imo
If you don't know how to implement it, you're implementing it wrong
Have GetCell(String)
and GetCellRange(String, String)
methodsYeah, my bad, it does
I don’t know if I can agree with that
Whether or not it would be sensible to implement it with indexers, I would still like to know if it is possible
Well you got your answer, no?
Not really, since I am still looking for what I wrote in the original post
Just
no?
Yes, that would solve the problem. @Sterbehilfe already proposed that. But using the indexer for ranges would then look look like this
someClass[“A1“, “A11“]
Instead of
someClass[“A1:A11“]
And the latter is what I am trying to achieve
Yeah that's not possible
And wouldn't make sense anyway
I found an example of what I am trying to do: https://ironsoftware.com/csharp/excel/examples/read-excel/
This undoubtedly works with
dynamic
Which you should avoid like the devil
You could argue that sure, other languages are able to specify multiple return types
But c# cannotYeah, I know that
Would you have an idea on how that has been implemented?
public dynamic this[string cellOrRange] => /* */;
Then in the getter body parse the input, check if it contains a :
, and do things accordingly
And then the rest of your code just becomes a nightmare
You could also return object
and cast it where you call it
Neither are even remotely okay solutions imoI think that seems to be the answer to my question, so thank you.