Domanda

I have just started learning C# and I have already a problem with encapsulation. In book there is a walkthrough how to build an application - it doesn't really matter what it's about.

I have 2 classes: Form1:

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        Farmer farmer;

        public Form1()
        {
            InitializeComponent();
            farmer = new Farmer(15, 30);
        }

        private void calculateButton_Click(object sender, EventArgs e)
        {
            Console.WriteLine("I need {0} bags of feed for {1} cows.", farmer.BagsOfFeed, farmer.NumberOfCows);
        }

        private void cowCount_ValueChanged(object sender, EventArgs e)
        {
            farmer.NumberOfCows = (int)cowCount.Value;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            farmer.BagsOfFeed = 5;
        }
    }
}

And class Farmer:

    namespace WindowsFormsApplication1
{
    class Farmer
    {
        public int BagsOfFeed;

        private int feedMultiplier;
        public int FeedMultiplier { get { return feedMultiplier; } }

        private int numberOfCows;
        public int NumberOfCows
        {
            get
            {
                return numberOfCows;
            }
            set
            {
                numberOfCows = value;
                BagsOfFeed = FeedMultiplier * numberOfCows;
            }
        }

        public Farmer(int numberOfCows, int feedMultiplier)
        {
            this.feedMultiplier = feedMultiplier;
            NumberOfCows = numberOfCows;
        }

    }
}

Because of the button1_click method in Form1 class the application doesn't work properly. In book it's written that I should change public BagsOfFeed field to property - so I do:

public int BagsOfFeed { get; set; }

And there's text after that:

Now you’ve got a property instead of a field. When C# sees this, it works exactly the same as if you had used a backing field (like the private numberOfCowsbehind the public NumberOfCowsproperty).

That hasn’t fixed our problem yet. But there’s an easy fix—just make it a read-only property: Try to rebuild your code—you’ll get an error on the line in the button that sets BagsOfFeedtelling you that the set accessor is inaccessible. You can’t modify BagsOfFeedfrom outside the Farmerclass—you’ll need to remove that line in order to get your code to compile, so remove the button andits event handlerfrom the form. Now your Farmerclass is better encapsulated!

And I don't really understand what's going on - my application still works the same as before. I guess I have to somehow make this property into read-only property, as it is said(but not explained) in this text. But how? I tried to erase the set part of the implementation, but then I have an error:

Error 1 'WindowsFormsApplication1.Farmer.BagsOfFeed.get' must declare a body because it is not marked abstract or extern. Automatically implemented properties must define both get and set accessors. C:\Users\Dess\documents\visual studio 2013\Projects\HeadFirst\WindowsFormsApplication1\Farmer.cs 12 33 ExerciseCowCount

And I have one additional question - what is the difference between normal field like public int Variable and public int Variable{get;set;}?

È stato utile?

Soluzione

And I don't really understand what's going on - my application still works the same as before.

It does, but differently. First you had a public int BagsOfFeed in the class that could be accessed and changed from anywhere in your program.

This would work:

farmer.BagsOfFeed= 1;
int i = farmer.BagsOfFeed; // i is now 1
farmer.BagsOfFeed= 5;
i = farmer.BagsOfFeed; // i is now 5

General guideline however is to not use public fields because they can be changed from anywhere in your program. There are situations (I know the book explains at least 1 example, about calculating party costs if I recall correctly) where that could mess up the output of your program.

To prevent that from happening we use properties to encapsulate the fields.

That hasn’t fixed our problem yet. But there’s an easy fix—just make it a read-only property: Try to rebuild your code—you’ll get an error on the line in the button that sets BagsOfFeedtelling you that the set accessor is inaccessible. You can’t modify BagsOfFeedfrom outside the Farmerclass.

What you are meant to do is make your property read only:

public int BagsOfFeed
{
    get;
    private set;
}

Note the private before the set. What this does is make the property so it can be get from anywhere but can only be set from inside that class. BagsOfFeed is now encapsulated.

In this particular example the property omits the need for implementing methods like farmer.getBagsOfFeed() and farmer.setBagsOfFeed(n)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top