none
how to return a abstract type (exercise of dotnetacademy.net) RRS feed

  • Question

  • Hello, 

    According to a challenge from dotnetacademy.net  I have to make this class : 

    public abstract class Answer
    {
        public int Score { get; set; }
    }

    now here I have to return a Answer : 

    protected string CreateAnswer 
    	{
    		get 
    		{
    			var input = Console.ReadLine();
    			return input; 
    		}
    		
    		set 
    		{
    			return Answer;     
    		}
    	}

    but when I do that I see this message :  Answer is a type, which is not valid in this context.

    How can I make this work 

    Thursday, September 28, 2017 8:14 PM

Answers

  • The purpose of this question is likely to convey why abstract classes (and interfaces) are useful. The example you are given is almost too simplistic to make use of abstract classes (and Answer doesn't really even need to be abstract). But let's work with it.

    What type of questions can there be on a "test" - multiple choice, true/false, discussion, etc. Each one would have a different type of answer. For multiple choice it is likely a letter or numeric selection. For true/false it is a boolean. For discussion it would be text. We want to represent all these different types of answers but still be able to work with them in general (because each question has an answer). So an abstract class (or interface) would be appropriate here. The base class provides access to the common functionality that all answers would share (score in this case). Everything else would need to be provided in derived types that represent the different types of answers.

    public abstract Answer
    {
       //Common members of all answers go here
       public int Score { get;set; }
    }
    
    //Answer for multiple choice questions
    public class MultipleChoiceAnswer : Answer
    {
       //The selected choice
       public int SelectedChoice { get; set; }
    }
    
    //Answer for true/false questions
    public class TrueFalseAnswer : Answer
    {
       public bool IsTrue { get; set; }
    }
    
    //Answer for discussion questions
    public class DiscussionAnswer : Answer
    {
       public string Text { get; set; }
    }
    

    The CreateAnswer method (which you defined as property but that isn't right) would be responsible for returning an appropriate Answer. But Answer is abstract. You can reference abstract types, use them as parameters and return types, etc but you cannot create an instance of one. So the CreateAnswer method would need to know what type of "answer" it is to create. Perhaps this would be based upon some parameters to the method or, more likely, a question (also abstract) would know how to create its own answer. 

    The calling code would work with the generic abstraction of Answer unless it needed to know what type of answer it was. In that case it would then need to identify the actual type of the answer (perhaps using pattern matching). But that is beyond the scope of this question.

    public Answer CreateAnswer (  )
    {
       do
       {
          Console.WriteLine("What type of answer do you want:");
          Console.WriteLine("T)rue/False");
          Console.WriteLine("M)ultiple Choice");
          Console.WriteLine("D)iscussion");
    
          var questionType = Console.ReadLine();
    
          switch (questionType.ToLower())
          {
             case "t" : return new TrueFalseAnswer();
             case "d" : return new DiscussionAnswer();
             case "m" : return new MultipleChoiceAnswer();
             default: Console.ReadLine("Bad answer");
          };
       } while (true);
    }

    If you want something more realistic then take a look at how Streams work in .NET. They are built this way. Also WebRequest and XmlReader/XmlWriter work this way.

    Michael Taylor
    http://www.michaeltaylorp3.net

    Friday, September 29, 2017 1:49 PM
    Moderator

All replies

  • Whats the link please

    Thanks, AT

    Thursday, September 28, 2017 8:21 PM
  • link : https://dotnetcademy.net/Learn/2051/Pages/5
    Thursday, September 28, 2017 8:23 PM
  • Hello Roelof1967,

    First of all, The set accessor resembles a method whose return type is void.It uses an implicit parameter called value, whose type is the type of the property.For your situation , the CreateAnswer is string type and you could define the property as below.

    protected string CreateAnswer
            {
                get
                {
                    var input = Console.ReadLine();
                    return input;
                }
    
                set
                {
                    CreateAnswer = value;
                }
            }

    >>how to return a abstract type (exercise of dotnetacademy.net)

    No, a abstract type can't be returned directly , You should return a subclasses of abstract classes . Something like below.

     
     class Program
        {
            protected Answer CreateAnswer1
            {
                get
                {
                    Answer input = CreateAnswer1;
                    return input;
                }
    
                set
                {
                    CreateAnswer1 = value;
                }
            }
    
            static void Main(string[] args)
            {
    
                Program program = new Program();
    
                program.CreateAnswer1=new imple_Answer(); /* invoke set accessor*/
    
                Answer answer = program.CreateAnswer1;  /* invoke get accessor */
            }
        }
    
        public abstract class Answer
        {
            public int Score { get; set; }
    
           
        }
        //define a imple_Answer class to implement abstract class.
        public class imple_Answer  : Answer
        {
    
        }

    There is a good article from MSDN, you should take a look at here.

    If you have any issues , please feel free to contact me.

    Sincerely,

    neil hu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, September 29, 2017 2:09 AM
    Moderator
  • yes, still one thing is not clear to me. 

    The challenge is stating : 

    The Question class should define a protected method named CreateAnswer that has a single string parameter. This method should be abstract so should not have an implementation within this class. The method must return an instance of Answer. The input parameter must be named input and represents the user's response from the question.

    but a abstract class has no body. How can I then return something like the challenge is saying. 

    Friday, September 29, 2017 5:23 AM
  • Hello Roelof1967,

    you couldn't create a abstract class instance. You should create a subclass to inher it  and then return the subclass instance.

     public abstract class Answer
        {
            public int Score { get; set; }
    
    
        }
        //define a subclass to implement abstract class.
        public class subAnswer : Answer
        {
    
        }

    and "return" statement as below

      public Answer Test() {
                 Answer answer = new subAnswer();
                return answer;
            }

    Sincerely,

    neil hu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, September 29, 2017 6:56 AM
    Moderator
  • oke, 

    After some trying I saw that they mean this as answer : 

    protected abstract Answer CreateAnswer(string input);

    Friday, September 29, 2017 7:34 AM
  • Hello Roelof1967,

    I'm not sure what you want, it is a abstract method , and you should implement it in subclass, you could get started from here.

    Sincerely,

    neil hu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, September 29, 2017 11:03 AM
    Moderator
  • Hi Roelof1967,

    The word "abstract" means that you can't create an instance of this class. You can make another class that inherits from the abstract class and create instances from the child (non-abstract) class.


    Thanks,
    Sabah Shariq

    [If a post helps to resolve your issue, please click the "Mark as Answer" of that post or click Answered "Vote as helpful" button of that post. By marking a post as Answered or Helpful, you help others find the answer faster. ]

    Friday, September 29, 2017 1:17 PM
    Moderator
  • The purpose of this question is likely to convey why abstract classes (and interfaces) are useful. The example you are given is almost too simplistic to make use of abstract classes (and Answer doesn't really even need to be abstract). But let's work with it.

    What type of questions can there be on a "test" - multiple choice, true/false, discussion, etc. Each one would have a different type of answer. For multiple choice it is likely a letter or numeric selection. For true/false it is a boolean. For discussion it would be text. We want to represent all these different types of answers but still be able to work with them in general (because each question has an answer). So an abstract class (or interface) would be appropriate here. The base class provides access to the common functionality that all answers would share (score in this case). Everything else would need to be provided in derived types that represent the different types of answers.

    public abstract Answer
    {
       //Common members of all answers go here
       public int Score { get;set; }
    }
    
    //Answer for multiple choice questions
    public class MultipleChoiceAnswer : Answer
    {
       //The selected choice
       public int SelectedChoice { get; set; }
    }
    
    //Answer for true/false questions
    public class TrueFalseAnswer : Answer
    {
       public bool IsTrue { get; set; }
    }
    
    //Answer for discussion questions
    public class DiscussionAnswer : Answer
    {
       public string Text { get; set; }
    }
    

    The CreateAnswer method (which you defined as property but that isn't right) would be responsible for returning an appropriate Answer. But Answer is abstract. You can reference abstract types, use them as parameters and return types, etc but you cannot create an instance of one. So the CreateAnswer method would need to know what type of "answer" it is to create. Perhaps this would be based upon some parameters to the method or, more likely, a question (also abstract) would know how to create its own answer. 

    The calling code would work with the generic abstraction of Answer unless it needed to know what type of answer it was. In that case it would then need to identify the actual type of the answer (perhaps using pattern matching). But that is beyond the scope of this question.

    public Answer CreateAnswer (  )
    {
       do
       {
          Console.WriteLine("What type of answer do you want:");
          Console.WriteLine("T)rue/False");
          Console.WriteLine("M)ultiple Choice");
          Console.WriteLine("D)iscussion");
    
          var questionType = Console.ReadLine();
    
          switch (questionType.ToLower())
          {
             case "t" : return new TrueFalseAnswer();
             case "d" : return new DiscussionAnswer();
             case "m" : return new MultipleChoiceAnswer();
             default: Console.ReadLine("Bad answer");
          };
       } while (true);
    }

    If you want something more realistic then take a look at how Streams work in .NET. They are built this way. Also WebRequest and XmlReader/XmlWriter work this way.

    Michael Taylor
    http://www.michaeltaylorp3.net

    Friday, September 29, 2017 1:49 PM
    Moderator