C# gurus, enlighten me

Tweak155

Lifer
Sep 23, 2003
11,449
264
126
Unfortunately I'm transitioning from a dead language, but into a great one learning - C#!

I feel like I'm learning concepts fairly quickly since I've only done a few hours of development. Afterall, learning one language does cover many BIG hurdles.

One question I find myself asking is why do types have methods? I can understand properties, but not methods. Why aren't these methods tied to the variables?

Example is string. Why is string.IsNullOrEmpty not tied to the string variables? You get great functions like Trim(), Contain(), etc - but they chose IsNullOrEmpty to be tied to the type.

What's the reasoning behind this? It makes me feel like I'm missing a very basic concept of the language.

Also any other tips on how I should view the language would be great!
 

KIAman

Diamond Member
Mar 7, 2001
3,342
23
81
One obvious reason from your example is that how can you call an instance method on an object that is null?
 

Train

Lifer
Jun 22, 2000
13,584
81
91
www.bing.com
I think you mean to say, why are some methods static instead of instance?

You are right, the inconsistency can be confusing. But I've read several explanations as to why in some instances they thought static methods would make more sense. There are a couple of code examples I've seen where the example using static methods does look more clear and readable, which should be the primary goal of any code.

That being said, if you want to make string.IsNullOrEmpty an instance method instead of static, you can do so by creating your own extension method.

Off the top of my head, try this, my syntax might be off:

public static IsNullOrEmpty(string this val)
{
return string.IsNullOrEmpty(val);
}

then you can do something like:
string myString = "blah";
if(myString.IsNullOrEmpty())
{
// blah...
}
 

Tweak155

Lifer
Sep 23, 2003
11,449
264
126
I think you mean to say, why are some methods static instead of instance?

You are right, the inconsistency can be confusing. But I've read several explanations as to why in some instances they thought static methods would make more sense. There are a couple of code examples I've seen where the example using static methods does look more clear and readable, which should be the primary goal of any code.

That being said, if you want to make string.IsNullOrEmpty an instance method instead of static, you can do so by creating your own extension method.

Off the top of my head, try this, my syntax might be off:

public static IsNullOrEmpty(string this val)
{
return string.IsNullOrEmpty(val);
}

then you can do something like:
string myString = "blah";
if(myString.IsNullOrEmpty())
{
// blah...
}

Wow, it didn't hit me that it was static vs non-static methods. That makes sense from that point of view. I knew it had to be simple, thanks!

EDIT:

I thought of another one, though. After this explanation I believe I may know the answer.

Let's say you have an XmlNode. Each XmlNode has a NextSibling which is null if one is not assigned.

Why does:

if (someNode.NextSibling == null)

Work... but

if (someNode.NextSibling.Equals(null))

Not work? Because Equals is an instance method and the NextSibling is null... thus you can't call the method since no memory has been allocated?
 
Last edited:

PhatoseAlpha

Platinum Member
Apr 10, 2005
2,131
21
81
The ==, and operators in general, actually function as static functions tied to the class. When you do NextSibling.Equals(null), you're specifically asking for the Equals method of nextSibling. If nextSibling is null, it doesn't actually have an equals method.


Actually, scratch all that. The sole important part is that operators are static methods of a class.
 
Last edited:

Mxylplyx

Diamond Member
Mar 21, 2007
4,197
101
106
Wow, it didn't hit me that it was static vs non-static methods. That makes sense from that point of view. I knew it had to be simple, thanks!

EDIT:

I thought of another one, though. After this explanation I believe I may know the answer.

Let's say you have an XmlNode. Each XmlNode has a NextSibling which is null if one is not assigned.

Why does:

if (someNode.NextSibling == null)

Work... but

if (someNode.NextSibling.Equals(null))

Not work? Because Equals is an instance method and the NextSibling is null... thus you can't call the method since no memory has been allocated?

All c# object instances derive from the base type System.Object, which is where common methods to all objects reside, such as "Equals" and "GetType". You cant call .Equals because there is no object instance assigned. The == null check is the correct way to determine if it is actually null.
 

Markbnj

Elite Member <br>Moderator Emeritus
Moderator
Sep 16, 2005
15,682
14
81
www.markbetz.net
if (someNode.NextSibling == null)

Work... but

if (someNode.NextSibling.Equals(null))

Not work? Because Equals is an instance method and the NextSibling is null... thus you can't call the method since no memory has been allocated?

What Train said, and more basically: they're not the same thing. In the first case you're testing for the equality of two references using a built-in operator. In the second you're calling a method that promises to tell you whether two things are equal, but you don't know anything about how it determines the answer.
 

KIAman

Diamond Member
Mar 7, 2001
3,342
23
81
How can you trim something that is null?

You can't. It will throw a nullreferenceexception. But it is good practice before you operate on a string object, you have to ensure it is not null and blank.

It looks so much prettier than checking for string == null then string == "".

Also methods such as IsNullOrEmpty came out before the microsoft came out with instance methods so they probably got lazy and left it static.
 

Tweak155

Lifer
Sep 23, 2003
11,449
264
126
You can't. It will throw a nullreferenceexception. But it is good practice before you operate on a string object, you have to ensure it is not null and blank.

It looks so much prettier than checking for string == null then string == "".

Also methods such as IsNullOrEmpty came out before the microsoft came out with instance methods so they probably got lazy and left it static.

Yeah I was just countering the argument.

It actually makes sense to me now to leave IsNullOrEmpty as it is a comparison to all instances to 2 distinct values. Null and empty do not change by instance, thus it should be a static method. I'll have to keep this view as I continue to write the application and see if I find any contradictions.
 

Tweak155

Lifer
Sep 23, 2003
11,449
264
126
Another noob question. The language I came from did not have inheritance but I did some C++ years ago so the concept isn't entirely lost on me. I was looking up the definition of the virtual modifier which makes sense to me, but I noticed something in it that I don't get.

Example class:
Code:
class TestClass
{
    public class Dimensions
    {
        public const double PI = Math.PI;
        protected double x, y;
        public Dimensions()
        {
        }
        public Dimensions(double x, double y)
        {
            this.x = x;
            this.y = y;
        }

        public virtual double Area()
        {
            return x * y;
        }
    }

    public class Circle : Dimensions
    {
        public Circle(double r) : base(r, 0)
        {
        }

        public override double Area()
        {
            return PI * x * x;
        }
    }

    class Sphere : Dimensions
    {
        public Sphere(double r) : base(r, 0)
        {
        }

        public override double Area()
        {
            return 4 * PI * x * x;
        }
    }

    class Cylinder : Dimensions
    {
        public Cylinder(double r, double h) : base(r, h)
        {
        }

        public override double Area()
        {
            return 2 * PI * x * x + 2 * PI * x * y;
        }
    }

    static void Main()
    {
        double r = 3.0, h = 5.0;
        Dimensions c = new Circle(r);
        Dimensions s = new Sphere(r);
        Dimensions l = new Cylinder(r, h);
        // Display results:
        Console.WriteLine("Area of Circle   = {0:F2}", c.Area());
        Console.WriteLine("Area of Sphere   = {0:F2}", s.Area());
        Console.WriteLine("Area of Cylinder = {0:F2}", l.Area());
    }
}

I'm confused where it says ": base(r,0)" and ": base(r,h)" ... etc.

I understand that base is derriving information from the base class, but in this example class I don't see an "r" in the base class. Also why is 0 used? Is this reversing the flow of information, I.e you're assigning properties to the base class that don't exist? I'm confused.

If you can give me an english translation of what "base(r, 0)" means, that would be of great help.

Thanks.
 

nickbits

Diamond Member
Mar 10, 2008
4,122
1
81
base(r, 0) and base(r, h) are calling the Dimensions(x, y) constructor. For the (r, 0) one, it is passing through r for x and 0 for y.
 
Last edited:

Train

Lifer
Jun 22, 2000
13,584
81
91
www.bing.com
base(r,0) would be the constructor for the base class, it's passing r from the "wrapper"

Basically if you call

var c = new Circle(5);

internally it is basically saying
c = new Dimensions(5, 0);

Because a circle only needs one size, so it's storing a radius and just passing in a zero for the other dimension
 

Tweak155

Lifer
Sep 23, 2003
11,449
264
126
base (r, 0) and base(r, h) are calling the Dimensions(x, y) constructor. For the (r, 0) one, it is passing through the r for x and 0 for y.

base(r,0) would be the constructor for the base class, it's passing r from the "wrapper"

Basically if you call

var c = new Circle(5);

internally it is basically saying
c = new Dimensions(5, 0);

Because a circle only needs one size, so it's storing a radius and just passing in a zero for the other dimension

Gotcha. Makes complete sense now. Glad to have resources here, you guys are great!
 

Tweak155

Lifer
Sep 23, 2003
11,449
264
126
Ok another question.

I thought, hey, I get the idea of inheritance, why not whip up an example. After attempting to do so, I realized I probably don't get the concept in practice.

So what I'm trying to do is create a simple game based on a popular card game around here. The game is Euchre. I don't think you need to understand the game to help me get the basics. I thought this would be a good example to work on because there is a deck, cards and players. Eventually I'll have a "table" or a "game board", but gotta get there first...

Anyway, here's code I came up with. All this does is auto-generate a deck of Euchre cards for me. I initially had Card inherit Deck because I viewed Cards as a sub-set of Deck. But I couldn't get it to work. There is only one Deck in this game which is why all the members are static.

Code:
    class Deck
    {
        const int DECK_SIZE = 24;

        private static string[] suits = { "Spades", "Clubs", "Diamonds", "Hearts" };
        private static int[] values = { 9, 10, 11, 12, 13, 14 };
        private static string[] faceValues = { "9", "10", "J", "Q", "K", "A" };

        private static int totalCards;
        private static int cardsUsed;

        //Public so I can see the created cards during debug
        public static Card[] cards = new Card[DECK_SIZE];

        public Deck()
        {
            totalCards = 0;
            cardsUsed = 0;

            for (int loopVar = 0; loopVar < 6; loopVar++)
            {
                for (int loopVar2 = 0; loopVar2 < 4; loopVar2++)
                {
                    Deck.cards[totalCards++] = new Card(suits[loopVar2], values[loopVar], faceValues[loopVar]);
                }
            }
        }

        public static int CardsRemaining()
        {
            return totalCards - cardsUsed;
        }


    }
    class Card
    {
        private string suit;
        private int value;
        private string faceValue;

        private bool dealt;

        public Card()
        {
            dealt = false;
        }
        public Card(string whichSuit, int whichValue, string whichFaceValue)
        {
            suit = whichSuit;
            value = whichValue;
            faceValue = whichFaceValue;
            dealt = false;
        }
    }

This compiles and works just fine, except I'm missing how I should integrate inheritance (maybe I made a bad example?). Also any pointers that I should learn now would be great, i.e how I should actually be defining a Card, the Deck or pointers in general (also good practice for naming variables in C#). I probably have bad practices coming from a non purely OO language.

Thanks.
 

Ancalagon44

Diamond Member
Feb 17, 2010
3,274
202
106
It doesnt sound like you are using inheritance correctly there.

Inheritance is used to specialize something. For instance, class car could inherit from class vehicle, because a car is a vehicle. However, not all vehicles are cars - some would be boats for instance.

But a card is not a deck, a deck contains cards. What you are looking for is something called composition - class deck contains many objects of type card.
 

Merad

Platinum Member
May 31, 2010
2,586
19
81
Anyway, here's code I came up with. All this does is auto-generate a deck of Euchre cards for me. I initially had Card inherit Deck because I viewed Cards as a sub-set of Deck. But I couldn't get it to work. There is only one Deck in this game which is why all the members are static.

I didn't look at your code, but that's not really how you'd want to use inheritance. Inheritance is used for an is-a relationship. It can be used for a has-a relationship, but that's generally bad practice.

For example:
An Automobile is a Vehicle. A PassengerCar and a UtilityVan are both Automobiles. The class structure would look like:

Code:
          Vehicle
             |
        Automobile
           /     \
UtilityVan   PassengerCar

You could have a Deck base class from which you implement different decks for various types of card games or something like that, but having Card inherit from Deck doesn't really make sense at all IMO.
 

Tweak155

Lifer
Sep 23, 2003
11,449
264
126
I guess I got confused because I saw inheritance examples with employees and company. Your explanations make sense though.

So if I called a class Cards I could then create Card for a specific type of Card, right?
 

Merad

Platinum Member
May 31, 2010
2,586
19
81
I guess I got confused because I saw inheritance examples with employees and company. Your explanations make sense though.

Ugh, sounds like a bad tutorial. You might use inheritance to create different types of employees, but the company -> employee relationship is "has a", and in that particular case it makes no sense at all to use inheritance. You'd want your company to have a member variable that is an array (or etc) of employees.

So if I called a class Cards I could then create Card for a specific type of Card, right?

Tentatively, yes depending on what you mean by "type of card". If you're talking about making a separate class for each individual card in a deck, that's going waaay overboard. However you might make different card subclasses for say, poker cards, uno cards, magic: the gathering cards, etc...
 

Tweak155

Lifer
Sep 23, 2003
11,449
264
126
Ugh, sounds like a bad tutorial. You might use inheritance to create different types of employees, but the company -> employee relationship is "has a", and in that particular case it makes no sense at all to use inheritance. You'd want your company to have a member variable that is an array (or etc) of employees.



Tentatively, yes depending on what you mean by "type of card". If you're talking about making a separate class for each individual card in a deck, that's going waaay overboard. However you might make different card subclasses for say, poker cards, uno cards, magic: the gathering cards, etc...

It's possible I just looked at the wrong points.

So maybe I should have a class called cards and a deck called euchre. I don't see a difference between just "deck" and "cards" as a deck is a collection of cards. Is there a logical gap I'm missing?

Maybe I should just ask how you'd approach it lol.
 

Mark R

Diamond Member
Oct 9, 1999
8,513
16
81
Class names should always be singular, as when you create an object, it is always a single object. If you create a class called "Cards", this is potentially confusing. Is it just a collection of cards? If so, how is it different from List<Card> or Card []?

A Deck, in your case would provide access to a collection of Cards. However, a Deck can be more than just an array of Cards. It can provide a defined set of cards, it can provide a method to pull a card off the top, or put it back on the bottom, shuffle the cards, etc.

You could then derive from Deck, to make different types of decks of cards - you could have FrenchDeck (for your generic 52 card pack), you could have MultipleDeck (where multiple packs are shuffled into a single large shoe), TarotDeck for playing with Tarot cards, etc.

Also, you are using static wrongly in your example code. Your cards collection in your Deck class should not be static - static fields are shared between all uses of that class. You almost never want to do that, 99.9% of times, you want an instance field, which is restricted to each specific object.
 

Tweak155

Lifer
Sep 23, 2003
11,449
264
126
Class names should always be singular, as when you create an object, it is always a single object. If you create a class called "Cards", this is potentially confusing. Is it just a collection of cards? If so, how is it different from List<Card> or Card []?

A Deck, in your case would provide access to a collection of Cards. However, a Deck can be more than just an array of Cards. It can provide a defined set of cards, it can provide a method to pull a card off the top, or put it back on the bottom, shuffle the cards, etc.

You could then derive from Deck, to make different types of decks of cards - you could have FrenchDeck (for your generic 52 card pack), you could have MultipleDeck (where multiple packs are shuffled into a single large shoe), TarotDeck for playing with Tarot cards, etc.

Also, you are using static wrongly in your example code. Your cards collection in your Deck class should not be static - static fields are shared between all uses of that class. You almost never want to do that, 99.9% of times, you want an instance field, which is restricted to each specific object.

I actually wanted to make the whole Deck static as I only want there to be 1 deck during the entire execution. But when I declared the class static it gave me problems. I might be able to fix it though.
 

Mark R

Diamond Member
Oct 9, 1999
8,513
16
81
I actually wanted to make the whole Deck static as I only want there to be 1 deck during the entire execution. But when I declared the class static it gave me problems. I might be able to fix it though.

If you only want to use 1 deck at a time, the deck should still be an instance class - you just only create one at a time.