Jump to content


 


Register a free account to unlock additional features at BleepingComputer.com
Welcome to BleepingComputer, a free community where people like yourself come together to discuss and learn how to use their computers. Using the site is easy and fun. As a guest, you can browse and view the various discussions in the forums, but can not create a new topic or reply to an existing one unless you are logged in. Other benefits of registering an account are subscribing to topics and forums, creating a blog, and having no ads shown anywhere on the site.


Click here to Register a free account now! or read our Welcome Guide to learn how to use this site.

Photo

Placeholder variables in C# custom classes


  • Please log in to reply
13 replies to this topic

#1 Galadriel

Galadriel

    Bleepin Elf


  • Malware Response Team
  • 2,753 posts
  • OFFLINE
  •  
  • Gender:Female
  • Location:Missouri, USA
  • Local time:10:28 PM

Posted 17 April 2010 - 08:18 PM

Hey guys, I've been trying to figure something out, and the google just isn't being very friendly right now. :thumbsup:

I have created a custom class/method which I use for inputs (to reduce the Console.Write's and WriteLine's I have to use). It's basically just a bunch of methods that accept a string (the prompt) and returns whichever value I asked for in the proper data type. Example:

myInteger = GetInput.GetInt("Enter test score: ");

Simple right? and very useful.... as I can avoid having to repeat the Write(), ReadLine() statements over and over, not to mention the conversion to integer... This works fine and I've used it in many projects with success.
I've also created a GetIntR() method, which accepts a string prompt, a low and high integer as arguments, for range checking specific input values. It calls GetInt to ensure the value to check is a valid integer first. Again, no problem with it that I see, I've used that with success also.

Here's the relevant portion of that custom class, so you guys can see first hand:

public class GetInput
	{
		public static int GetInt(string prompt) //accepts a string prompt as an argument, and returns an integer.
		{
			string data = "";
			int value = 0;
			bool anError = false;

			do
			{
				Console.Write(prompt);  //Display the prompt as passed to the method.
				data = Console.ReadLine().Trim(); //assign input to the data string, dropping leading and trailing spaces.
				try
				{
					value = Convert.ToInt32(data);   //attempt to convert data to an integer.
					anError = false;				 //If conversion is succesful, assign false to anError
				}
				catch (Exception ex)	//If conversion unsuccesful, display error message and assign true to anError.
				{
					Console.WriteLine("******ERROR! This program only accepts valid numerical entries!******");
					Console.WriteLine("{0} is not a valid integer!", data);
					anError = true;
				}
			} while (anError); //Loop until anError returns false.
			
			return value;		   //Return result of conversion.
		} //End of GetInt
		
		public static int GetIntR(string prompt, int low, int high) //accepts a string prompt, a low and a high integer to determine range, and returns an integer if within range.
		{
			int value;
			value = GetInt(prompt);			 //Calls the GetInt method to get valid integer.
			while (value < low || value > high) //As long as the value isn't within the specified range, loop.
			{
				Console.WriteLine("*** {0} must be between {1} and {2}.", value, low, high);
				Console.WriteLine("*** Try again.");
				value = GetInt(prompt);		 //Get a valid integer using the GetInt method again, so the check can be made when loop begins anew.
			} //End of while loop.
			return value;		   //Return result of in-range conversion.
		} //End of GetIntR

	} //End of class

Now I want to use it to get a bunch of test scores and put them in an array. I want the prompt to read "Enter test score #1" for the first prompt, then #2, #3 and so on... for each subsequent prompt. Normally, I would use Console.Write("Enter test score #{0}: ", count +1); to ask, but I want to use my GetInput class here, and it won't let me use the placeholder in the prompt.
My question is this: Can I use a placeholder in a custom method call? Do I have to code the placeholder as an argument in the actual method, or am I totally trying to mix apples and oranges here? Halp?

Here's a "working" main, as I have it now. I've had to remove the placeholder to get it to build and run, everything works as intended, but I want the display on the prompt to the user to read the number of entries... (I know, I'm fussy, what can I say?)

Yes, this is a school assignment, though the GetInput class is optional, I've been trying to figure it out. I can always revert to doing it all manually with Console.Write()s, but I want to learn something beyond the easy stuff....

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ProjExerciseSixOne
{
	class testScoresArray
	{
		static void Main()
		{
			const int MAX_CLASS_SIZE = 5;
			int[] scores = new int[MAX_CLASS_SIZE];
			double total = 0;
			double average = 0;
			int count = 0;

			scores[count] = GetInput.GetIntR("Enter test score or '-1' to exit: ", -1, 200);
			while (scores[count] >= 0)
			{
				count++;
				if (count == MAX_CLASS_SIZE)
				{
					Console.WriteLine("\nError - Array is full");
					return;
				}

				scores[count] = GetInput.GetIntR("Enter test score or -1 to end: ", -1, 200);
			} //End while

			Array.Sort(scores, 0, count);

			Console.WriteLine("\n\nThe scores you entered are:");
			for (int x = 0; x < count; x++)
			{
				Console.WriteLine("Test Score #{0} is {1}.", x + 1, scores[x]);
				total += scores[x];
			}

			average = total / count;

			Console.WriteLine("\nThe average of the {0} scores you entered is {1}", count, average.ToString("F2"));
		}
	}
}

I cemna prestar aen. Han mathon ne nen. Han mathon ne chae. A han noston ne 'wilith. - Galadriel
'The avatar is changed; I can feel it in the water, I can feel it in the earth, I can smell it in the air.'

Phear teh ceiling cat, for he is roofkittehd! - Basement Cat

I'm a Bleeping Folder, are you? - Join BC in the fight against diseases - Click here
Become a BleepingComputer fan: Facebook

BC AdBot (Login to Remove)

 


#2 CyberSorcerer

CyberSorcerer

    Malware Reverse Engineer


  • Members
  • 99 posts
  • OFFLINE
  •  
  • Gender:Male
  • Location:Las Vegas
  • Local time:09:28 PM

Posted 17 April 2010 - 10:00 PM

Hello Galadriel,

Well being this is a school project I don't want to actually give away an answer. I'm not sure how far along you are in class so I just changed your code a small bit. Go ahead and fun it, especially causing your Exception to kick in, and see the output.

I'm using Visual Studio 2008 Professional not sure what you use in class.

Have fun :thumbsup:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class GetInput
{
	public static int GetInt(string prompt) //accepts a string prompt as an argument, and returns an integer.
	{
		string data = "";
		int value = 0;
		bool anError = false;

		do
		{
			Console.Write(prompt);  //Display the prompt as passed to the method.
			data = Console.ReadLine().Trim(); //assign input to the data string, dropping leading and trailing spaces.
			try
			{
				value = Convert.ToInt32(data);   //attempt to convert data to an integer.
				anError = false;				 //If conversion is succesful, assign false to anError
			}
			catch (Exception ex)	//If conversion unsuccesful, display error message and assign true to anError.
			{
				Console.WriteLine("******ERROR! This program only accepts valid numerical entries!******");
				Console.WriteLine("{0} is not a valid integer!", ex); //CHANGED FROM data you have to use a variable when you declare on and ex is declared.
				anError = true;
			}
		} while (anError); //Loop until anError returns false.

		return value;		   //Return result of conversion.
	} //End of GetInt

	public static int GetIntR(string prompt, int low, int high) //accepts a string prompt, a low and a high integer to determine range, and returns an integer if within range.
	{
		int value;
		value = GetInt(prompt);			 //Calls the GetInt method to get valid integer.
		while (value < low || value > high) //As long as the value isn't within the specified range, loop.
		{
			Console.WriteLine("*** {0} must be between {1} and {2}.", value, low, high);
			Console.WriteLine("*** Try again.");
			value = GetInt(prompt);		 //Get a valid integer using the GetInt method again, so the check can be made when loop begins anew.
		} //End of while loop.
		return value;		   //Return result of in-range conversion.
	} //End of GetIntR

} //End of class

namespace ProjExerciseSixOne
{
	class testScoresArray
	{
		static void Main()
		{
			const int MAX_CLASS_SIZE = 5;
			int[] scores = new int[MAX_CLASS_SIZE];
			double total = 0;
			double average = 0;
			int count = 0;
			int value = 0;
			//int low = 0;
			//int high = 0;

			scores[count] = GetInput.GetIntR("Enter test score or '-1' to exit: ", -1, 200);
			while (scores[count] >= 0)
			{
				count++;
				if (count == MAX_CLASS_SIZE)
				{
					Console.WriteLine("\nError - Array is full");
					Console.ReadLine();
					return;
				}
				
				scores[count] = GetInput.GetIntR("Enter test score or -1 to end: ", -1, 200);
				
				value++;
			} //End while

			Array.Sort(scores, 0, count);

			Console.WriteLine("\n\nThe scores you entered are:");
			for (int x = 0; x < count; x++)
			{
				Console.WriteLine("Test Score #{0} is {1}.", x + 1, scores[x]);
				total += scores[x];
			}

			average = total / count;

			Console.WriteLine("\nThe average of the {0} scores you entered is {1}", count, average.ToString("F2"));
			Console.ReadLine(); // Press Enter to exit
		}
	}
}


#3 Galadriel

Galadriel

    Bleepin Elf

  • Topic Starter

  • Malware Response Team
  • 2,753 posts
  • OFFLINE
  •  
  • Gender:Female
  • Location:Missouri, USA
  • Local time:10:28 PM

Posted 17 April 2010 - 11:09 PM

I use VS Pro 2008 also.

CyberSorcerer, at first glance, the changes you proposed are pretty minor, considering, and I understand them. The exception 'warning' is inconsequential, as I don't care, want or need to display the exception, only to catch it. Concerning the Console.ReadLine()s you added where the program 'ends', I can understand the logic of using them, and if I were to build and release this as an exe, I would. In this case, I test with "Start without debugging" (CTRL+F5), which always asks to hit a key to exit and Prof doesn't want actual exe, only the code in a word file, with screenies of tests performed (in the case of a console app like this one, I can just copy/paste from cmd window.)

Not sure why you declared and initialized value in Main and added the value++ in the while loop though, it serves no purpose that I see. value is not used in that class/method. Like I said in my original post, the GetInput.GetIntR and GetInput.GetInt are methods in a custom class (a seperate cs file) and any variable used in those methods does not transfer over to Main, unless returned (where they are stored in a different variable) or referred to directly if I understand my method calls right. :thumbsup:

In any case, none of the above really touches what I was asking. I do appreciate you taking the time to look though! :flowers:

Edited to add: To be perfectly clear, I have no issues with the logic portion of my program whatsoever, it works as intended the way I have it. All I am trying to achieve, is something like the placeholder does in the Console.Write() argument as I stated in the first post.
I know how to do it manually, but that means I need to add a lot more code to my main, just for a little display issue. I can do that very easily. I think it just would be more efficient and helpful if I learn how to code it in a method myself.

Example of what I want to do, in the loop, but using my input class, instead of Console.WriteLine() each time:

Console.WriteLine("Enter test score #{0}: ", count +1);
scores[count] = Console.ReadLine(); <- skipping the conversion for now, as it isn't relevant to what I want to accomplish, I know how to do that already. Just making a point.

See where I'm going?

Edited by Galadriel, 17 April 2010 - 11:18 PM.

I cemna prestar aen. Han mathon ne nen. Han mathon ne chae. A han noston ne 'wilith. - Galadriel
'The avatar is changed; I can feel it in the water, I can feel it in the earth, I can smell it in the air.'

Phear teh ceiling cat, for he is roofkittehd! - Basement Cat

I'm a Bleeping Folder, are you? - Join BC in the fight against diseases - Click here
Become a BleepingComputer fan: Facebook

#4 CyberSorcerer

CyberSorcerer

    Malware Reverse Engineer


  • Members
  • 99 posts
  • OFFLINE
  •  
  • Gender:Male
  • Location:Las Vegas
  • Local time:09:28 PM

Posted 17 April 2010 - 11:52 PM

yea, sorry about the value variable. That is from my playing around with your code as I always like messing up code. Thought I had all my playing around taken out.

No need to continue explain further sense we are talking on IRC now... LOL

CyberSorcerer

#5 Billy O'Neal

Billy O'Neal

    Visual C++ STL Maintainer


  • Malware Response Team
  • 12,304 posts
  • OFFLINE
  •  
  • Gender:Male
  • Location:Redmond, Washington
  • Local time:09:28 PM

Posted 18 April 2010 - 12:06 AM

Hello, Galadriel :thumbsup:

I'm not going to give you code (being a school assignment after all), but I would accomplish this using the Template Method Pattern. That should allow you to combine the GetInt methods into a single method that accomplishes what you want, and additionally allows you to modify the output on a case-by-case basis.

Hope that helps,

Billy3
Twitter - My statements do not establish the official position of Microsoft Corporation, and are my own personal opinion. (But you already knew that, right?)
Posted Image

#6 Galadriel

Galadriel

    Bleepin Elf

  • Topic Starter

  • Malware Response Team
  • 2,753 posts
  • OFFLINE
  •  
  • Gender:Female
  • Location:Missouri, USA
  • Local time:10:28 PM

Posted 18 April 2010 - 12:23 AM

After talking it over further with CyberSorcerer in IRC, and based also on what you posted Billy, I am kinda way over my head with this. It seemed like such a simple detail, something I could have added simply, guess I was mistaken. :thumbsup: Wouldn't be the first time I took on more than I could chew...

I'm starting to understand why using the custom class was optional now! Evil prof.... :flowers:
I cemna prestar aen. Han mathon ne nen. Han mathon ne chae. A han noston ne 'wilith. - Galadriel
'The avatar is changed; I can feel it in the water, I can feel it in the earth, I can smell it in the air.'

Phear teh ceiling cat, for he is roofkittehd! - Basement Cat

I'm a Bleeping Folder, are you? - Join BC in the fight against diseases - Click here
Become a BleepingComputer fan: Facebook

#7 Billy O'Neal

Billy O'Neal

    Visual C++ STL Maintainer


  • Malware Response Team
  • 12,304 posts
  • OFFLINE
  •  
  • Gender:Male
  • Location:Redmond, Washington
  • Local time:09:28 PM

Posted 18 April 2010 - 12:42 AM

based also on what you posted Billy ... I am kinda way over my head with this.


Sometimes there are design patterns like this that are relatively complicated that occur over and over again in software design. Template Method is one of these. It lets you get rid of a ton of duplicated code and yet still have something that can have vastly different behavior. At first glance it looks complicated, but once you recognize the pattern, you can understand code that uses the pattern quickly, and you can apply it to make your own code easier. EDIT: To be clear, you don't need to use patterns like this and it's unreasonable for your professor to require them, but they're proven designs that have led to reusable code for other developers and which work outside of any application specific domain.

That said, these things typically aren't taught in schools -- even those teaching programming. I learned about this from talking to other developers as an intern at PreEmptive. Sometimes talking with those who have first-hand experience making real software makes all the difference in the world.

If you're interested in learning about any of these patterns, I recommend the original Gang of Four (or GoF) book, which goes much farther into making these into understandable design items. I'd mail you my copy, but unfortunately it's kindle-ized.

Have a nice night,
Billy3

Edited by Billy O'Neal, 18 April 2010 - 12:45 AM.

Twitter - My statements do not establish the official position of Microsoft Corporation, and are my own personal opinion. (But you already knew that, right?)
Posted Image

#8 Galadriel

Galadriel

    Bleepin Elf

  • Topic Starter

  • Malware Response Team
  • 2,753 posts
  • OFFLINE
  •  
  • Gender:Female
  • Location:Missouri, USA
  • Local time:10:28 PM

Posted 18 April 2010 - 01:11 AM

Time for sleeps. Like I said elsewhere, my respect for programmers was renewed... and multiplied to infinity. Also, I need more Ibuprofen, obviously this puny bottle isn't gonna last. :thumbsup:

Thanks to everyone for "enlightening" me. (Though I'm actually more confused than I originally was after this.) Maybe with more sleep and less stress I'll be able to grasp more of it, but for now, I'm dain bramaged.

@ Billy, just cuz... Posted Image
I cemna prestar aen. Han mathon ne nen. Han mathon ne chae. A han noston ne 'wilith. - Galadriel
'The avatar is changed; I can feel it in the water, I can feel it in the earth, I can smell it in the air.'

Phear teh ceiling cat, for he is roofkittehd! - Basement Cat

I'm a Bleeping Folder, are you? - Join BC in the fight against diseases - Click here
Become a BleepingComputer fan: Facebook

#9 housec

housec

  • Members
  • 15 posts
  • OFFLINE
  •  
  • Local time:05:28 AM

Posted 03 August 2010 - 01:14 AM

Just killing time waiting while my lappy is pretty dead from some nasty malware thingamy,
Thought I'd put my 2 pence in...
Don't quite see how template helps here... Over engineering much?
In this example, would result in more code, not less? Base class defining the parse checking, and additional virtual verify method? Seems more hassle than it'd be worth..?

Anyhoo, quick solution I knocked up (Might not build thou.. not tested in studio, - sorry lazy, :thumbsup: )
[codebox]
class testScoresArray
{
static void Main()
{
GetInput gi = new GetInput();
while (gi.GetInt("Enter test score #" + (gi.Count + 1).ToString() + " (or '-1' to exit): ", -1, 200)) ;

Console.WriteLine("\n\nThe scores you entered are:");
Console.WriteLine(gi.ToString());
Console.WriteLine("\nThe average of the {0} scores you entered is {1}", gi.Count, gi.Average.ToString("F2"));

Console.ReadKey();
}
}

public class GetInput
{
public int Total
{
get
{
return _scores.Sum();
}
}

private List<int> _scores = new List<int>();

public override string ToString()
{
IEnumerable<string> vals = _scores.OrderBy(a => a).Select((a, i) => "Test Score " + (i + 1).ToString() + " is " + a.ToString() + "." + Environment.NewLine);
return vals.Aggregate(new StringBuilder(), (sb, a) => sb.Append(a)).ToString();
}

public float Average
{
get
{
return (float)Total / _scores.Count;
}
}

public int Count
{
get
{
return _scores.Count;
}
}

public bool GetInt(string prompt, int? low, int? high) //accepts a string prompt as an argument, and returns an integer.
{
string data = "";

Console.Write(prompt); //Display the prompt as passed to the method.
data = Console.ReadLine().Trim(); //assign input to the data string, dropping leading and trailing spaces.

if (data == "-1")
return false;

int i;

if (int.TryParse(data, out i))
{
if (high.HasValue && low.HasValue && (i < low.Value || i > high.Value))
{
Console.WriteLine("*** {0} must be between {1} and {2}.", i, low.Value, high.Value);
Console.WriteLine("*** Try again.");
}
else
{
_scores.Add(i);
}
}
else
{
Console.WriteLine("******ERROR! This program only accepts valid numerical entries!******");
Console.WriteLine("{0} is not a valid integer!", data);
}
return true;
} //End of GetInt

public void GetInt(string prompt) //accepts a string prompt, a low and a high integer to determine range, and returns an integer if within range.
{
GetInt(prompt, null, null);
} //End of GetIntR

} //End of class
[/codebox]
-C

Edited by housec84, 03 August 2010 - 01:16 AM.


#10 Billy O'Neal

Billy O'Neal

    Visual C++ STL Maintainer


  • Malware Response Team
  • 12,304 posts
  • OFFLINE
  •  
  • Gender:Male
  • Location:Redmond, Washington
  • Local time:09:28 PM

Posted 03 August 2010 - 08:12 AM

Err... that's not a template method. Template method is an inheritance pattern. If you are referring to the use of `List<t>`, in C# those are called generics, not templates.
Twitter - My statements do not establish the official position of Microsoft Corporation, and are my own personal opinion. (But you already knew that, right?)
Posted Image

#11 housec

housec

  • Members
  • 15 posts
  • OFFLINE
  •  
  • Local time:05:28 AM

Posted 03 August 2010 - 08:27 AM

Eh? I obviously wasn't giving an example of template 'pattern'
Sorry if that wasn't clear...
Didn't quite see the point of giving an example of that for a problem I didn't believe gained any benefit from it, as said...

#12 Billy O'Neal

Billy O'Neal

    Visual C++ STL Maintainer


  • Malware Response Team
  • 12,304 posts
  • OFFLINE
  •  
  • Gender:Male
  • Location:Redmond, Washington
  • Local time:09:28 PM

Posted 03 August 2010 - 08:39 AM

No, template method would not help you here. That said, it might eventually make sense to refactor that into a strategy pattern or template method if you wanted to be able to change how scores are displayed or calculated without changing the guts of what you're doing, which is the process of Read -> Calculate -> Print. A template method would define that basic framework, and you could plug in any piece of that in a derived class to combine functionality.

It's all about taking code and putting it into more separate parts, and building functionality by putting those parts together instead of having one big sticky mess of a class.
Twitter - My statements do not establish the official position of Microsoft Corporation, and are my own personal opinion. (But you already knew that, right?)
Posted Image

#13 housec

housec

  • Members
  • 15 posts
  • OFFLINE
  •  
  • Local time:05:28 AM

Posted 03 August 2010 - 09:17 AM

... :thumbsup:

Eventually the key word, ;)
Can't disagree with constant re-factoring thou!
For a solution that is < a 1000 lines of code, your just adding unnecessary plumbing unless you 'know' your going to be extending later, or it actually requires that functionality now - As you said if you require multiple render, input, and process methods.
Generally not brilliant practice to have a base class(or interface) that only has 1 subclass. Always been quite a fan of occam's razor applied to code :trumpet:

Let's be clear... I'm not advocating the lack of OO principles and good design. But in 'some' (few) cases, it is over-engineering, which costs time/money :flowers:

Anyhoo kinda gone away with this a touch...
Was just abit bored with my laptop being an infested piece of junk so figured I'd play with some code to pass the time, :inlove:

-C

#14 Billy O'Neal

Billy O'Neal

    Visual C++ STL Maintainer


  • Malware Response Team
  • 12,304 posts
  • OFFLINE
  •  
  • Gender:Male
  • Location:Redmond, Washington
  • Local time:09:28 PM

Posted 03 August 2010 - 09:41 AM

Well, duh. Nobody ever said every system needed to be patterned all to hell. It just can be useful if it's a commonly extended area of your program to make it easy to plug in new components without changing other components.
Twitter - My statements do not establish the official position of Microsoft Corporation, and are my own personal opinion. (But you already knew that, right?)
Posted Image




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users