Home > Archive > C# > April 2006 > How to use dictonary
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
How to use dictonary
|
|
| FabrizioSW@gmail.com 2006-04-25, 7:09 pm |
| Hi all in my class i declared a struct like this
public class MyClass
{
private struct contaStatiLink
{
public int offline;
public int online;
public contaStatiLink(int Offline,int Online)
{
offline = Offline;
online = Online;
}
}
now i want to use a dictonary it contains the structure type,
this is the code:
Dictionary<string, contaStatiLink> StatiLink = new Dictionary<string,
contaStatiLink>();
after elaboration i've to incremente for each key the value in the
properties of the struct as follow
StatiLink[sKey].online++;
but i get the follow erorr :
Error 3 Cannot modify the return value of
'System.Collections.Generic.Dictionary<string,contaStatiLink>.this[string]'
because it is not a variable.
what's wrong in my code?
thanks in advance.
| |
| Jeff Suddeth 2006-04-25, 7:09 pm |
| It probably has something to do with the fact that structs are value types,
though I have not read anything explaining why this should be the case. May
be the Dictionary boxes the thing and you have to unbox it before you can
use it? That is just a guess, as I thought the point of using generics was
so that we could have a strongly typed collection. In any case, I think the
following code does something like what you need.
class Program
{
struct MyData
{
public int x;
public int y;
}
static void Main(string[] args)
{
Dictionary<string, MyData> dictionary = new Dictionary<string,
MyData>();
dictionary["one"] = new MyData();
dictionary["two"] = new MyData();
dictionary["three"] = new MyData();
dictionary["four"] = new MyData();
MyData d = (MyData)dictionary["one"];
d.x++;
dictionary["one"] = d;
Console.WriteLine("press enter to exit");
Console.ReadLine();
}
}
<FabrizioSW@gmail.com> wrote in message
news:1145874308.148838.294760@u72g2000cwu.googlegroups.com...
> Hi all in my class i declared a struct like this
>
> public class MyClass
> {
>
> private struct contaStatiLink
> {
> public int offline;
> public int online;
>
> public contaStatiLink(int Offline,int Online)
> {
> offline = Offline;
> online = Online;
> }
> }
>
> now i want to use a dictonary it contains the structure type,
> this is the code:
>
> Dictionary<string, contaStatiLink> StatiLink = new Dictionary<string,
> contaStatiLink>();
>
> after elaboration i've to incremente for each key the value in the
> properties of the struct as follow
>
> StatiLink[sKey].online++;
>
> but i get the follow erorr :
>
> Error 3 Cannot modify the return value of
> 'System.Collections.Generic.Dictionary<string,contaStatiLink>.this[string]'
> because it is not a variable.
>
> what's wrong in my code?
>
> thanks in advance.
>
| |
| Bruce Wood 2006-04-25, 7:09 pm |
| First of all, I would suggest that you want contaStatiLink to be a
class, not a struct. If you change it to a class, your code will work
as expected.
Second, though, you probably don't want public fields. You should
declare the fields private and then provide the functionality you need
via properties and methods. For example,
private class ContaStatiLink
{
private int offline;
private int online;
public contaStatiLink(int Offline,int Online)
{
offline = Offline;
online = Online;
}
public int Online { get { return this.online; } }
public int Offline { get { return this.offline; } }
public void IncrementOnline() { this.online++; }
public void IncrementOffline() { this.offline++; }
}
Finally, I can explain what is going on in your current code, and why
it doesn't work the way you expected.
> It probably has something to do with the fact that structs are value types....
Jeff was right: it is because structs are value types, but it is not
because of boxing and unboxing. .NET 2.0 generic collections do not
box.
Remember that value types are always _copied_ whenever they are
assigned, passed as arguments, or returned as results from methods.
That is the point of using a struct: to get this behaviour.
The accessor for a collection:
StatiLink[sKey]
is really just a method call. It calls a function that takes "sKey" as
its argument and returns a contaStatiLink struct. Note the word
"returns" there: because it's just a method that returns a value, it
returns a _temporary copy_ of the value. So, the indexer looks up the
correct contaStatiLink struct in the dictionary, then _copies_ the
value of that struct onto the stack, and returns the copy to the
caller.
If you then try to modify that temporary copy, like this:
StatiLink[sKey].online++;
the compiler (correctly) warns you that you aren't doing anything
useful. You're not changing the contaStatiLink struct that is stored in
the dictionary. Instead, you're just changing a temporary copy on the
stack, which will then be thrown away. The compiler knows that's not a
useful thing to do, and complains.
Remember, structs are value types: they're copied everywhere. As such,
making mutable (changeable) structs is a questionable thing to do. It
usually means that you want a class, not a struct (although not
always).
If you insist upon keeping contaStatiLink a struct (which I don't
suggest; I suggest that you make it a class), then you would be better
off doing what Jeff suggested, or something like this:
StatiLink[sKey] = new contaStatiLink(StatiLink[sKey].offline,
StatiLink[sKey].online + 1);
which is pretty awkward, don't you think? A class would be much cleaner.
| |
| FabrizioSW@gmail.com 2006-04-26, 4:02 am |
|
Bruce Wood wrote:
> First of all, I would suggest that you want contaStatiLink to be a
> class, not a struct. If you change it to a class, your code will work
> as expected.
>
> Second, though, you probably don't want public fields. You should
> declare the fields private and then provide the functionality you need
> via properties and methods. For example,
>
> private class ContaStatiLink
> {
> private int offline;
> private int online;
>
> public contaStatiLink(int Offline,int Online)
> {
> offline = Offline;
> online = Online;
> }
>
> public int Online { get { return this.online; } }
> public int Offline { get { return this.offline; } }
> public void IncrementOnline() { this.online++; }
> public void IncrementOffline() { this.offline++; }
> }
>
> Finally, I can explain what is going on in your current code, and why
> it doesn't work the way you expected.
>
>
> Jeff was right: it is because structs are value types, but it is not
> because of boxing and unboxing. .NET 2.0 generic collections do not
> box.
>
> Remember that value types are always _copied_ whenever they are
> assigned, passed as arguments, or returned as results from methods.
> That is the point of using a struct: to get this behaviour.
>
> The accessor for a collection:
>
> StatiLink[sKey]
>
> is really just a method call. It calls a function that takes "sKey" as
> its argument and returns a contaStatiLink struct. Note the word
> "returns" there: because it's just a method that returns a value, it
> returns a _temporary copy_ of the value. So, the indexer looks up the
> correct contaStatiLink struct in the dictionary, then _copies_ the
> value of that struct onto the stack, and returns the copy to the
> caller.
>
> If you then try to modify that temporary copy, like this:
>
> StatiLink[sKey].online++;
>
> the compiler (correctly) warns you that you aren't doing anything
> useful. You're not changing the contaStatiLink struct that is stored in
> the dictionary. Instead, you're just changing a temporary copy on the
> stack, which will then be thrown away. The compiler knows that's not a
> useful thing to do, and complains.
>
> Remember, structs are value types: they're copied everywhere. As such,
> making mutable (changeable) structs is a questionable thing to do. It
> usually means that you want a class, not a struct (although not
> always).
>
> If you insist upon keeping contaStatiLink a struct (which I don't
> suggest; I suggest that you make it a class), then you would be better
> off doing what Jeff suggested, or something like this:
>
> StatiLink[sKey] = new contaStatiLink(StatiLink[sKey].offline,
> StatiLink[sKey].online + 1);
>
> which is pretty awkward, don't you think? A class would be much cleaner.
Hi, very thanks for large and complete explanation.
But i'm a little bit about using the struct, in fact when i've
to choice a struct and when the class?
what's difference between declare a private member and use the public
property to get and set its value? or simply declare it public?
thanks again.
| |
| Bruce Wood 2006-04-27, 7:03 pm |
| Here are several threads on struct vs class:
http://groups.google.com/group/micr...13bcc64b8438f65
http://groups.google.com/group/micr...ac9dc1229bb833a
As for why use properties rather than expose public fields, my first
comment would be to look carefully at what I did in the sample I
posted: I made it impossible to modify the counters in any way except
increment them. By exposing them as public fields, you give the
"public" (other classes) the capacity to do things like this:
myContaStatiLink.offline = 10;
myContaStatiLink.online -= 56;
Do you really want your callers to be able to do _absolutely anything_
with these values? Aren't they counters? If they are, then it makes
sense to allow your callers to do exactly three things with them: 1)
look at them; 2) reset them; 3) increment them. If you expose them as
public fields then you give up this level of control.
Here are some more threads about why properties are generally a better
idea than public fields:
http://groups.google.com/group/micr...0a2f8e8a665405d
http://groups.google.com/group/micr...6e907d9dbcdc1d4
.... and there are many more. Just search the newsgroup for "field
property public" for more. :-)
|
|
|
|
|