|
Introduction
Just about everything is a heap object when you are using C#. Only elementary
native types like int are treated as value types. But there are two value types
in C# that are pretty much more useful that first glances would tell you. They
are the enum and struct types. Very few tutorials even cover these topics, but
they have their own uses. And both of them are a lot more efficient than classes
and you can use them in place of classes when they meet your requirements to
improve performance.
Enums
Enums are basically a set of named constants. They are declared in C# using
the enum keyword. Every enum type
automatically derives from System.Enum and thus we can use
System.Enum methods on our Enums. Enums are value types and are created
on the stack and not on the heap. You don't have to use new
to create an enum type. Declaring an enum
is a little like setting the members of an array as shown below.
enum Rating {Poor, Average, Okay, Good, Excellent}
You can pass enums to member functions just as if they were normal objects.
And you can perform arithmetic on enums too. For example we can write two
functions, one to increment our enum and the other to
decrement our enum.
Rating IncrementRating(Rating r)
{
if(r == Rating.Excellent)
return r;
else
return r+1;
}
Rating DecrementRating(Rating r)
{
if(r == Rating.Poor)
return r;
else
return r-1;
}
Both functions take a Rating object as argument and return back a Rating
object. Now we can simply call these functions from elsewhere.
for (Rating r1 = Rating.Poor;
r1 < Rating.Excellent ;
r1 = IncrementRating(r1))
{
Console.WriteLine(r1);
}
Console.WriteLine();
for (Rating r2 = Rating.Excellent;
r2 > Rating.Poor;
r2 = DecrementRating(r2))
{
Console.WriteLine(r2);
}
And here is a sample code snippet showing how you can call
System.Enum methods on our Enum object. We call the
GetNames method which retrieves an array of the names of the constants in
the enumeration.
foreach(string s in Rating.GetNames(typeof(Rating)))
Console.WriteLine(s);
Where to use enums
Quite often we have situations where a class method takes as an argument a
custom option. Let's say we have some kind of file access class and there is a
file open method that has a parameter that might be one of read-mode,
write-mode, read-write-mode, create-mode and append-mode. Now you might think of
adding five static member fields to your class for these modes. Wrong approach!
Declare and use an enumeration which is a whole lot more efficient and is better
programming practice in my opinion.
Structs
In C++ a struct is just about the same as a class for
all purposes except in the default access modifier for methods. In C# a
struct are a pale puny version of a class. I am not
sure why this was done so, but perhaps they decided to have a clear distinction
between structs and classes. Here are some of the drastic areas where classes
and structs differ in functionality.
- structs are stack objects and however much you try you cannot create them
on the heap
- structs cannot inherit from other structs though they can derive from
interfaces
- You cannot declare a default constructor for a
struct,
your constructors must have parameters
- The constructor is called only if you create your
struct
using new, if you simply declare the struct
just as in declaring a native type like int, you
must explicitly set each member's value before you can use the
struct
struct Student : IGrade
{
public int maths;
public int english;
public int csharp;
public int GetTot()
{
return maths+english+csharp;
}
public Student(int y)
{
maths = english = csharp = y;
}
public string GetGrade()
{
if(GetTot() > 240 )
return "Brilliant";
if(GetTot() > 140 )
return "Passed";
return "Failed";
}
}
interface IGrade
{
string GetGrade();
}
Well, now let's take a look at how we can use our struct.
Student s1 = new Student();
Console.WriteLine(s1.GetTot());
Console.WriteLine(s1.GetGrade());
0
Failed
Here the default constructor gets called. This is automatically implemented
for us and we cannot have our own default parameter-less constructor. The
default parameter-less constructor simply initializes all values to their
zero-equivalents. This is why we get a 0 as the total.
Student s2;
s2.maths = s2.english = s2.csharp = 50;
Console.WriteLine(s2.GetTot());
Console.WriteLine(s2.GetGrade());
150
Passed
Because we haven't used new, the constructor does not get called. Of all the
silly features this one must win the annual contest by a long way. I see no sane
reason why this must be so. Anyway you have to initialize all the member fields.
If you comment out the line that does the initialization you will get a compiler
error :- Use of unassigned local variable 's2'
Student s3 = new Student(90);
Console.WriteLine(s3.GetTot());
Console.WriteLine(s3.GetGrade());
270
Brilliant
This time we use our custom constructor that takes an int
as argument.
When to use structs
Because structs are value types they would be easier to handle and more
efficient that classes. When you find that you are using a class mostly for
storing a set of values, you must replace those classes with structs. When you
declare arrays of structs because they are created on the heap, efficiency again
improves. Because if they were classes each class object would need to have
memory allocated on the heap and their references would be stored. In fact lots
of classes within the .NET framework are actually structs. For example
System.Drawing.Point is actually a struct and not a
class.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 31 (Total in Forum: 31) (Refresh) | FirstPrevNext |
|
|
 |
|
|
Hi all, I am really new to C# and I am having a problem with structs. in C++ it is perfectly common do something like: struct foo { int bar[10]; char otherthing[20]; };
but in c# I tried doing: public struct foo { int[] bar = new int[10]; byte[] other = new byte[20]; } but I got the error 'cannot have instance field initializers in structs'; So, how can I have arrays in structs?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hi Nishant, One thing that's often overlooked is how to store a bunch of data in a program that will not be changing.
I'm building a coordinate conversion library in C# and would like to store all the various ellipsoid info in the dll, not an XML file or other external file. What would you recommend for a library component.
I plan to use an enum and a struct to define ellipsoids, but with 30 or more, how can I properly initialize all the fields.
enum eEllipsoidType {type1,type2,type3}
struct Ellipsoid { eEllipsoidType etype; double a,b; }
Then later, ArrayList alEllipsoid = new ArrayList[];
Will a resource file be useful.
In C++, you can do this, but C# does not allow initialization.  struct { double val; int index; } DefaultInput[] = {{60,0},{70,0},{20,0},{14.73,0},{2,0},{1,0},{0.6,0},{0.78,0},{1000,0}};
Another example from C++: const UnitList::Conversion ucTemp[] = {{"Fahrenheit",1,0},{"Celsius",1.8,32},{"Rankine",1,-459.67},{"Kelvins",1.8,-459.67}};
but again, this is another form of structure initialization.
What is the best practice for including a lot of constant parameter data that will be included in the dll when compiled into a library component.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi Nish,
I decided to quit using classes when I wrote the following code:
public struct Demo { public string value; } ArrayList al = new ArrayList(); al.Add(new Demo); ((Demo)al[0]).value = “Test”;
..and got an error from the compiler: "The left-hand side of an assignment must be a variable, property or indexer"  I know, I know: an ArrayList pointer is not possible to 'point' to a variable that has been instantiated on the stack (which is the case for structs). Is there any way to overcome this limitation? The only way I found was to copy the Demo in the list to temporary variable, delete it from the list, change its value and re-insert it to list (quite cumbersome!) Of course if you put "class" instead of "struct" all goes well..
Cheers, Dimitris
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Actually you mean you quit using structs (as opposed to classes).
And personally I don't like using structs either. Usually when you're dealing with data you're dealing with sets of it. So you need to be able to store N of them. And you want to be able to make changes without having to remember to put the changed value back. Lazy? maybe... but I stopped using structs a long time ago.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
in Net 2.0 you can use generics to create collections of structs (this wasn't available when this discussion was started)
for example
List<Demo> demolist = new List<Demo>(); Demo demo1; demo1.value = 12345; demolist.Add(demo1); ... demolist[n].value = ...;
the list is allocated on the heap so it will persist beyond the scope where the added structures were created as long as the reference to it is kept for use. of course this means a lot of copying around when initializing the list since the semantics are still by value so it's better to use a class, but this is possible.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi, i know that typedef structs creates an aliases for a particular struct in C++. i m trying to convert .h c++ files to a namespace in C#.net so that i use C++ DLL in my C# application. one of the structs in C++ is something like typedef struct mystruct {....} mystruct1, *mystruct2; since typedef is used, mystruct1 and *mystruct2 are aliases to mystruct. how can i acheive the same (i.e aliasses in c#)? i can subtitute mystruct1 and *mystruct2 in the C# namespace (which i am creating) by mystruct. but i am not sure if they are used in the DLL? your help is greatly appreciated. i am new to DLL and C# thanks arssa2020@yahoo.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Imagin this code ( with mistakes )
class A { enum mynumber { one, two, three } } class B : A { public B() { //Does anybody know somme thing similar to this or // how to do this base.nynumber.Add( four ); // to use like int a = mynumber.one; int b = mynumber.four; } }
my question you know, is this or some thing similar possible. Thanks
Santi srlopez@rps.es
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hmmm... Sort of. It won't be an enum, but you can do this: [edit]This is simplified code, you'll need to implement some conversions and operators, but that's the skeleton[/edit]
struct A { public static A one; public static A two; public static A three; }
struct B : A { public static A four; }
I see dumb people
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
srlopez wrote: Thanks... is the same idea, but ... struct in c# can inherits? I not sure. Yes, it can.
I see dumb people
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Mate, you cannot subclass structs either. Try your code in VS2005.
Enums are structs and both are subject to this limitation.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
You can't add enum element dynamically, you can use Dictionary, SIMILAR TO enum.
Sample Code:
class ClassA { protected Dictionary dic = new Dictionary(); public ClassA() { dic.Add("one", 1); dic.Add("two", 2); dic.Add("three", 3); } }
class ClassB: ClassA { public int this[string s] { get { foreach (KeyValuePair kv in dic) { if (kv.Key.Equals(s)) { return kv.Value; } } return Int32.MinValue; } } public ClassB() { dic.Add("four", 4); } }
static void Main(string[] args) { ClassB b = new ClassB(); Console.WriteLine(b["three"]); }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thanks Nish for the article! But...isn't it odd that code like the following is legal in C#?
Rating average = Rating.Poor + 1;
This is the syntax that underlies IncrementRating and DecrementRating in your article. It's all perfectly legal C#, and you are careful not to go beyond the defined range. But I gotta ask, Is it a good idea to manipulate enums like this? It's not legal in C++.
I can see two drawbacks, and I bet you can guess what they are. First, there is the maintenance problem that arises when the enum changes. When you amend the Rating enum, you also have to double check that IncrementRating and DecrementRating still work. In the United States at least, the pressure of normal grade inflation will soon require the enum to become:
enum Rating {Poor, Average, Okay, Good, Excellent, Awesome, Fantastic}
That may not be so much of a problem in other parts of the world where education standards are better maintained.
Second, the method of incrementing and decrementing enums is not general because enum values don't have to occupy a contiguous range:
enum Rating {Poor=40, Average=60, Okay=75, Good=85, Excellent=92}
Adding and subtracting a constant like 1 will not walk you from one enum value to the next in a case like this. In fact, you will land in a crack:
Rating above_average = Rating.Average + 1; // legal, = 51
What seems strange and inconsistent is that you can assign above_average as shown above, but can't do it directly:
Rating above_average = 51; // error!
So what do you think? Given problems like these, is the C# language flawed with regard to its handling of enum?
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
Consistency.
All of the value types require that you initialize them before use.
Does anyone out their believe that int or char should have a default value.
int i; char c;
Console.WriteLine( "Int i is {0}, Char c is '{c}'" );
-------------- Output
Int i is 0, Char c is 'a'
--------------
Obviously, assumptions like this could lead to problems.
Uninitialized value types have always been a problem in C/C++ programming. C# simply doesn't allow them. I believe that the behavior produces a consistency across ALL value types.
Uninitialized reference types default to null. Value types must be assigned before use, no nullness (as far as the compiler is concerned).
Will T Smith
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I needed to enumerate through an Enum and could not figure it out. I then remembered your article and just knew you would have an example in here as to how to do it. An voila, you did, I did and it rocked! 
thanks again Nish.
Paul Watson Bluegrass Cape Town, South Africa Ray Cassick wrote: Well I am not female, not gay and I am not Paul Watson
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Nishant S wrote: I guess you now qualify as one of the most vociferous supporters of my articles.
Do I get a badge? 
Actually I am quite suprised and appalled at the low rating this article has recieved. Sure it is not some revelation of great altruistic knowledge, but it really explains some fundamental concepts very well and provides great samples.
I wish we could see who voted what for what article Then we can go pester the low-voters and ask them "Why?"
Paul Watson Bluegrass Cape Town, South Africa Ray Cassick wrote: Well I am not female, not gay and I am not Paul Watson
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Another question 
Basically I have an XML file which persists certain data and I guess really represents a class... (maybe I should just serialise my objects? hmm...)
The class has an enum (same as my previous question) with those three "constants", Article, Image and Other. Now in the XML file there is an attribute named type and it holds either Article, Image or Other.
Currently when I pull from the XML file I am using a switch block to assign the right enum "constant" to the object instance. e.g. (pseudo code) If xmlnode.type = "article" then cItem.type = ContentType.Article
I think that is pretty lame and it will get out of hand when more content types are introduced.
So my question is: Is there a better way to do it? Is there a way to sort of "inform" the system that Article in the XML file is equal to ContentType.Article?
There must be, because that will just make enums rock even more! ta (hope my question does not sound too stupid )
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Paul,
See this code :-
enum Rating {Poor, Average, Okay, Good, Excellent} class Class1 { [STAThread] static void Main(string[] args) { for(Rating r = Rating.Poor; r<=Rating.Excellent; r++) Console.WriteLine((int)r); } }
It'll show 0,1,2,3,4 on screen. So basically they are integeres starting from 0 (unless you specify otherwise).
So perhaps you could do this in your XML :-
<blah type=x />
where x is an integer. Now simply read this x and cast it to ContentType.Article. That should work. This is clearer from the following code snippet :-
Rating q = (Rating)3; Console.WriteLine(q);
This will output "Good" on the screen.
If my solution sounds silly, well sorry about that Paul. Gave it my best shot 
Nish
Author of the romantic comedy
Summer Love and Some more Cricket [New Win]
Review by Shog9 Click here for review[NW]
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Nishant S wrote: If my solution sounds silly, well sorry about that Paul. Gave it my best shot
LOL Nish, no your solution was certainly an answer and one I did not think of (do you have a backpack to carry your extra brain btw? )
The only thing is that that means I have to use numbers instead of text in the XML file, which just makes the XML file harder to read and understand outside of the application.
I guess what I have to do is do what you suggested above and then create an XML Schema which has it's own enum defining 1 as Article, 2 as Image etc. It is actually a better way, but damn that is going to take me some time to do and I was hoping for a lazy-ass-programmer way
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Paul Watson wrote: The only thing is that that means I have to use numbers instead of text in the XML file
You can use the Enum.Parse method to convert the text value back to the enum value.
Untested code follows 
enum Foo { Bar, Baz } .... Foo foo = (Foo) Enum.Parse(typeof(Foo), "Bar", true); The first parameter is the Type representing the enum, the second parameter is the string version, and the third parameter tells the method if it should ignore case.
It will throw an Argument exception if "Bar" isn't a valid member of the enum.
HTH,
James Sig code stolen from David Wulff
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Nishant S wrote: BTW the sig is nice; who is he anyway
He's one of the major participaters on DevelopMentor's DOTNET-* lists. He certainly has a way with words
James Sig code stolen from David Wulff
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
James T. Johnson wrote: The first parameter is the Type representing the enum, the second parameter is the string version, and the third parameter tells the method if it should ignore case.
*Paul bows at JTJ's feet* I would offer up a virgin as thanks, but all the virgins I know... oh wait I don't know any. Anyway.
Thanks James that is just brilliant. Enums rock even more now. And that case insensitive setting is a blessing as sometimes my XML docs are hand coded and people are not too careful about using the right case.
Thanks once again! 
Isn't it brilliant how MS with the .NET Framework have "guessed" exactly what we need? So many times I have gone "Damn I wish it could do that" only to discover after a bit of digging that there is something that can do it in the framework. Lovely stuff.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|