Converting a Dictionary to an array?

G

Gustaf

This is two questions in one really. First, I wonder how to convert the
values in a Dictionary to an array. Here's the dictionary:

private Dictionary<Uri, Schema> schemas = new Dictionary<Uri, Schema>();

Uri is the System.Uri class, and Schema is a class I made. Now, I want
the class where this Dictionary is contained to have a property that
returns all the values in this Dictionary. Like such:

public Schema[] Schemas

How do I implement this property? I can figure out how to do it, but
that involves looping through all the elements in the dictionary, and
that's probably not the way it's meant to be done. I assume there must
be a one-liner solution, like the ArrayList.ToArray() method. I found
the Dictionary.Values property, but can't figure out how to make that
into an array.

My second question is about best practices. I wonder if it makes sense
to have a property that returns an array of Schema objects, rather than
returning another kind of collection? I want a basic and general
interface outwards, something that doesn't assume too much in terms of
what packages are used in the calling class. Then, is an object array
the best choice?

Gustaf
 
D

Dave Sexton

Hi Gustaf,
This is two questions in one really. First, I wonder how to convert the
values in a Dictionary to an array. Here's the dictionary:

private Dictionary<Uri, Schema> schemas = new Dictionary<Uri, Schema>();

Uri is the System.Uri class, and Schema is a class I made. Now, I want the
class where this Dictionary is contained to have a property that returns
all the values in this Dictionary. Like such:

public Schema[] Schemas

How do I implement this property? I can figure out how to do it, but that
involves looping through all the elements in the dictionary, and that's
probably not the way it's meant to be done. I assume there must be a
one-liner solution, like the ArrayList.ToArray() method. I found the
Dictionary.Values property, but can't figure out how to make that into an
array.

public Schema[] Schemas
{
get
{
Schema[] array = new Schema[schemas.Count];
schemas.Values.CopyTo(array, 0);
return array;
}
}
My second question is about best practices. I wonder if it makes sense to
have a property that returns an array of Schema objects, rather than
returning another kind of collection? I want a basic and general interface
outwards, something that doesn't assume too much in terms of what packages
are used in the calling class. Then, is an object array the best choice?

That depends on what the caller will be doing with the return value, but
most likely an array would be your best choice since it only represents a
copy of the values in your dictionary. Any other return type might be
misleading.
 
J

Jon Shemitz

Gustaf said:
public Schema[] Schemas

How do I implement this property? I can figure out how to do it, but
that involves looping through all the elements in the dictionary, and
that's probably not the way it's meant to be done. I assume there must
be a one-liner solution, like the ArrayList.ToArray() method. I found
the Dictionary.Values property, but can't figure out how to make that
into an array.

You can do this as a one-liner, but it's not pretty:

return new List<Schema>(schemas.Values).ToArray();

If you don't want to get fired after your next code review, you
probably ought to break this into two statements:

My second question is about best practices. I wonder if it makes sense
to have a property that returns an array of Schema objects, rather than
returning another kind of collection? I want a basic and general
interface outwards, something that doesn't assume too much in terms of
what packages are used in the calling class. Then, is an object array
the best choice?

Probably not. The approach that makes the fewest assumptions and
wastes the fewest cycles is to just expose a

public IEnumerable<Schema> Values
{
get { return schemas.Values; }
}

Then, if your callers just want to enumerate, they can do so without
any waste of time or memory. If they want a List<Schema>, they can
easily generate one; ditto if they want a Schema[].
 
L

Lucian Wischik

Gustaf said:
I found the Dictionary.Values property, but can't figure out how to make that
into an array.
My second question is about best practices. I wonder if it makes sense
to have a property that returns an array of Schema objects, rather than
returning another kind of collection? I want a basic and general
interface outwards, something that doesn't assume too much in terms of
what packages are used in the calling class. Then, is an object array
the best choice?

I don't think an object array is the best choice. Dictionary.Values
seems perfect for what you need. And I think it's more elegant for
objects to return ICollection<T> or IEnumerable<T> rather than T[].
(e.g. returning an IEnumerable<T> would let you completely rewrite
your code for returning the thing, perhaps even using the wonderful
"yield return").
 
M

Mark Rae

You can do this as a one-liner, but it's not pretty:

return new List<Schema>(schemas.Values).ToArray();

If you don't want to get fired after your next code review

I've never understood that attitude at all - there is absolutely *nothing*
wrong with that single line of code...
 
D

Dave Sexton

Hi Mark,

Well, it's iterating the entire collection to copy it into a new object,
just so it can do another copy internally again to return it as an array,
simply to save 2 lines of code :)
 
J

Jon Shemitz

Mark said:
I've never understood that attitude at all - there is absolutely *nothing*
wrong with that single line of code...

It's sort of hard to parse, especially if you're a bit unclear on C#
operator precedence. And, imho, you can be a perfectly fine C#
programmer - comfortable with all the operators and idioms - and still
be a bit unclear on C# operator precedence. I mean **15** levels of
precedence? It makes a lot of sense to ignore that and use
"unnecessary" parens.
 
J

Jon Shemitz

Dave said:
Well, it's iterating the entire collection to copy it into a new object,
just so it can do another copy internally again to return it as an array,
simply to save 2 lines of code :)

Yeah - I was typing under the influence of the impression that Keys
and Values were IEnumerable<T>s, not collections. (It certainly seems
like that would be a better design.)
 
F

Fabio Z

Dave Sexton said:
Hi Mark,

Well, it's iterating the entire collection to copy it into a new object,
just so it can do another copy internally again to return it as an array,
simply to save 2 lines of code :)

Premised that I also prefere the second solution, I really don't see
difference into generated IL.
I would be more worried about the fact that a class shouldn't return a
Something<T> class to the extern.
 
D

Dave Sexton

Hi Fabio,
Premised that I also prefere the second solution, I really don't see
difference into generated IL.

The IL is certainly different. Consider what's inside of the List<T>
constructor. The parameter being supplied is IEnumerable<T>, used to copy
the entire collection into the new List<T> object. Then, another method
call is made (ToArray) to perform a similar operation as the code that I
supplied does in 2 lines of code.

The difference is that a new object is created (List<T>) and an extra
iteration over the entire collection occurs (inside its constructor), which
could be costly if the collection is large or the operation is performed
many times.
I would be more worried about the fact that a class shouldn't return a
Something<T> class to the extern.

Why? Haven't you returned IEnumerable<T> from a property before, or any
generic type for that matter?

In this particular situation I think returning an Array is probably the best
choice, but if the OP decided that consumers of the class would be better
off having an IEnumerable<T> or ICollection<T>, with very good reason, then
that should be acceptable. The reason why I think Array is better is
because IEnumerable<T> may give the impression that the collection of
Schemas can always be iterated in the same order, which is false since the
OP is using a Dictionary (IIRC). ICollection<T> can be modified, which
gives the impression that the Schemas property itself will change, but it
won't since it's being backed by the values of a dictionary. Both are
misleading to callers.

I usually assume a property that returns an Array to be a copy of the values
stored within a class, which isn't misleading to callers since that's what
the OP requires. It's IEnumerable and If consumers require a collection
they can fill a List<T>, just like in the one-line example that you prefer
(although it would be external to the class and so caller's choice).
 
F

Fabio Z

Dave Sexton said:
The IL is certainly different.

Really different :)
I did a test, and the second solution produces EXACTLY the same IL (except
the fact that a second variabe and a call reference to it are created, so
the first solution would be even optimized).

Why? Haven't you returned IEnumerable<T> from a property before, or any
generic type for that matter?

Because it is a bad practice.
You should expose a

class MyTypeCollection : List<MyType> {}

instead of a List<MyType>.
 
D

Dave Sexton

Hi Fabio,
Really different :)
I did a test, and the second solution produces EXACTLY the same IL (except
the fact that a second variabe and a call reference to it are created, so
the first solution would be even optimized).

I'm really not sure what you mean here. There is definitely a difference
between the two examples both in the IL that is produced and in the IL that
is executed. You shouldn't base your opinion solely on the IL that is
produced anyway - it's the IL being processed that makes the important
difference in this case.
Because it is a bad practice.
You should expose a

class MyTypeCollection : List<MyType> {}

instead of a List<MyType>.

I disagree that using a generic type as a property is bad practice.

When I need to expose a list of items from a class I may return an IList<T>
(not a concrete implementation, although I don't think that's particularly
important). Wrapping every list returned by a property in a custom
collection is overkill unless you need to extend the default behavior, IMO.

And you lose type-safety if you return IEnumerable over IEnumerable<T>, for
example.
 
L

Lucian Wischik

Dave Sexton said:
In this particular situation I think returning an Array is probably the best
choice, but if the OP decided that consumers of the class would be better
off having an IEnumerable<T> or ICollection<T>, with very good reason, then
that should be acceptable. The reason why I think Array is better is
because IEnumerable<T> may give the impression that the collection of
Schemas can always be iterated in the same order, which is false since the
OP is using a Dictionary (IIRC). ICollection<T> can be modified, which
gives the impression that the Schemas property itself will change, but it
won't since it's being backed by the values of a dictionary. Both are
misleading to callers.

I don't think IEnumerable<T> is misleading. After all,
Dictionary.Values returns an IEnumerable without the order-guarantee
you're reading.

As for ICollection, the advice from FxCop is to wrap it up inside a
ReadOnlyCollection<T> when you return it. That seems fine.
 
D

Dave Sexton

Hi Lucian,
I don't think IEnumerable<T> is misleading. After all,
Dictionary.Values returns an IEnumerable without the order-guarantee
you're reading.

But that's on a Dictionary, which already has specific semantics for which
you are aware. What if you saw IEnumerable<Schema> on some arbitrary class
and you didn't (and probably shouldn't) know that the class was using a
Dictionary internally? Returning an Array is much clearer, IMO.

Another reason why I prefer Array over IEnumerable<T> when returning a list
of values is because Array can be cast to IEnumerable<T> anyway.

Also, IEnumerable<T> is usually not enough for consumers since consumers
generally require a list, not an iterator (although with the constructors of
As for ICollection, the advice from FxCop is to wrap it up inside a
ReadOnlyCollection<T> when you return it. That seems fine.

Yes, that seems like good advice, although returning an Array is just as
good and more common, IMO.
 
F

Fabio Z

"Dave Sexton" <dave@jwa[remove.this]online.com> ha scritto nel messaggio

I'm really not sure what you mean here. There is definitely a difference
between the two examples both in the IL that is produced and in the IL
that is executed.

if 1 produces A and 2 produces A I don't know what is the doubt about if
will be executed A rather than A :)

I disagree that using a generic type as a property is bad practice.

When I need to expose a list of items from a class I may return an
IList<T> (not a concrete implementation, although I don't think that's
particularly important). Wrapping every list returned by a property in a
custom collection is overkill unless you need to extend the default
behavior, IMO.

It's good if you expose a class MyClass<T>, but you should not return
MyClass<T> to the extern.
And you lose type-safety if you return IEnumerable over IEnumerable<T>,
for example.

This is not the same.
I told to expose

IMyBaseClassEnumerable : IEnumerable<MyBaseClass>

I think you have a base class that is not object ;)
 
D

Dave Sexton

Hi Fabio,
if 1 produces A and 2 produces A I don't know what is the doubt about if
will be executed A rather than A :)

Well, I've explained it three times already so I really don't know what
other evidence there is to submit. Yes, the two solutions both have the
same outcome, but how they get there is quite different.

<snip>
 
A

Adam Clauss

Dave Sexton said:
Hi Fabio,

Well, I've explained it three times already so I really don't know what
other evidence there is to submit. Yes, the two solutions both have the
same outcome, but how they get there is quite different.

<snip>

Having read this thread - I'm going to throw out that I think you guys are
talking about two different sets of code :)

I *think* Fabio is referring to the following examples given by Jon Shemitz:

return new List<Schema>(schemas.Values).ToArray();

vs

List<Schema> Values = new List<Schema>(schemas.Values);
return Values.ToArray();

To which, I would agree they probably generate the same IL.

Dave, I think you are referring to what you originally posted:
Schema[] array = new Schema[schemas.Count];
schemas.Values.CopyTo(array, 0);
return array;

vs

What Jon posted.

To which I also agree - the first is more effecient as it does not have to
iterate across the collection twice.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top