Section 2: Classes - Design a StackOverflow Post Design a class called Post. This class models a StackOverflow post. It should have properties
  for title, description and the date/time it was created. We should be able to up-vote or down-vote
  a post. We should also be able to see the current vote value. In the main method, create a post,
  up-vote and down-vote it a few times and then display the the current vote value.
  
  In this exercise, you will learn that a StackOverflow post should provide methods for up-voting
  and down-voting. You should not give the ability to set the Vote property from the outside,
  because otherwise, you may accidentally change the votes of a class to 0 or to a random
  number. And this is how we create bugs in our programs. The class should always protect its
  state and hide its implementation detail.
  
  Educational tip: The aim of this exercise is to help you understand that classes should
  encapsulate data AND behaviour around that data. Many developers (even those with years of
  experience) tend to create classes that are purely data containers, and other classes that are
  purely behaviour (methods) providers. This is not object-oriented programming. This is
  procedural programming. Such programs are very fragile. Making a change breaks many parts
  of the code.


That is the information given to me for this exercise in my C# tutorial.  The following is my working code.  Still trying to grasp Object Oriented Programming.  I believe I did set the properties so that you can get the information but not give the ability to set the Vote property from the outside by setting the property to Private.  I also tried to protect the state of voting so that you could not up-vote or down-vote consecutively, yet allow it to change your vote and show the vote count along with protecting the state of the vote count.

Anyhow if anyone can see how to improve on this, point out a better way, or teach me something new I would greatly appreciate it.

using System;

namespace ExerciseTwo
{
    class Post
    {
        public string Title { get; set; }
        public string Description { get; set; }
        public DateTime TimeDateCreated { get; private set; }
        public int VoteCount { get; private set; }
        private bool HasVotedUp;
        private bool HasVotedDown;

        public Post(string title, string description)
        {
            Title = title;
            Description = description;
            TimeDateCreated = DateTime.UtcNow;
            VoteCount = 0;
        }

        public void VoteUp()
        {
            if (HasVotedUp)
            {
                throw new Exception("You have already up-voted.");
            }
            else
            {
                VoteCount++;
                HasVotedUp = true;
                HasVotedDown = false;
            }
        }

        public void VoteDown()
        {
            if (HasVotedDown)
            {
                throw new Exception("You have already down-voted.");
            }
            else
            {
                VoteCount--;
                HasVotedDown = true;
                HasVotedUp = false;
            }
        }
    }
}


Script to demo how it could work.

namespace ExerciseTwo
{
    class Program
    {
        static void Main()
        {
            Post post = new Post("Does my post work?", "Test to see if my post works.");
            System.Console.WriteLine($"Title: {post.Title}");
            System.Console.WriteLine($"Description: {post.Description}");
            System.Console.WriteLine($"Date Created: {post.TimeDateCreated}");
            System.Console.WriteLine($"Post Count: {post.VoteCount}");
            post.VoteDown();
            System.Console.WriteLine($"Post Count: {post.VoteCount}");
            post.VoteUp();
            System.Console.WriteLine($"Post Count: {post.VoteCount}");
        }
    }
}


Thank you for your help!
I don't know which version of C# you use, but as of C# 6 it's possible to set initial values on property definition, which has 2 advantages:


Can eyeball the initial values quickly by looking at the property definitions.
Doesn't require you to copy the same initial value assignment code into additional constructors you may create.


Example initial value definition:

public int VoteCount { get; private set; } = 0;


Also in the case of int with initial value 0 you don't have to explicitly set it because when an instance of the class is initialized all the ints are initialized with the default value 0 unless you specified otherwise. Just like the bools are false by default (you didn't set them in the constructor).



You could add another layer of protection to the creation date:

public DateTime TimeDateCreated { get; } = DateTime.UtcNow;


Without defining a setter, TimeDateCreated is set when you create an instance of Post and can never be changed again for that instance. It makes sense here because the only date you'd ever want to change on a post is the date it was edited.



Not a big deal for now, but it's better to develop early the habit of giving good variable names, this means being descriptive, concise and consistent with the naming of things around the code base. Most of your names are good, but TimeDateCreated is a bit counter-intuitive because once you'll get used to the name DateTime you'll expect this property to be named DateTimeCreated.



It's good that you protected VoteCount, but your vote function does something unwanted: if you first downvote and then upvote, you will be back to 0 votes but without the ability to upvote. I suggest you rethink this part of the code.