问题
I have a foreach loop and I would like to call all properties of a certain class in the foreach loops so I don't have to write it all out.
The class I have created
public Person()
{
firstname = "";
surname = "";
haircolor = "";
eyecolor = "";
weight = 0;
height = 0;
age = 0;
}
This is the code I am trying to compact
Console.WriteLine("Please enter the next persons firstname");//new person user input (firstname)
addperson.firstname = Console.ReadLine();
Console.WriteLine("Enter the persons surname");//surname
addperson.surname = Console.ReadLine();
Console.WriteLine("Enter " + addperson.name + "'s hair color");//hair color
addperson.haircolor = Console.ReadLine();
Console.WriteLine("Enter the age of " + addperson.firstname);//age
addperson.age = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Enter the weight of " + addperson.firstname);//weight
addperson.weight = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Enter the height of " + addperson.firstname);//height
addperson.height = Convert.ToDouble(Console.ReadLine());
I have started on the foreach loop, I would like a way to compact all of that code to a loop
foreach (Person.)
{
Console.WriteLine("Please enter " +addperson.ToString);
Person.addperson = Console.ReadLine();
}
Any help would be much appreciated
回答1:
you need to use reflection to be able to loop over each property dynamically, personally i wont change it to use reflection since reflection has performance penalties, but here is the code for your reference:
Change Class fields to properties:
public class Person
{
public string firstname {get;set;}
public string surname {get;set;}
public string haircolor {get;set;}
public string eyecolor {get;set;}
public string weight {get;set;}
public string height {get;set;}
public string age {get;set;}
}
Write this code in your main method:
Person addperson = new Person();
PropertyInfo[] props = addperson.GetType().GetProperties();
foreach(PropertyInfo prop in props)
{
Console.WriteLine("Please enter " + prop.Name.ToString());
string input = Console.ReadLine();
prop.SetValue(addperson, input, null);
}
EDIT:
This line of code:
PropertyInfo[] props = addperson.GetType().GetProperties();
Returns all the public properties of the Person type (class), then each PropertyInfo object discovers the attributes of the property and provides access to its metadata.
回答2:
I'd do it like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace YourNameSpace
{
class Program
{
static void Main(string[] args)
{
Person p = GetPersonFromUserInput();
}
private static Person GetPersonFromUserInput()
{
Person p = new Person();
Type t = typeof(Person);
foreach (PropertyInfo pi in t.GetProperties().Where(pi => pi.GetCustomAttribute<PromptAttribute>() != null))
{
PromptAttribute attribute = pi.GetCustomAttribute<PromptAttribute>();
Console.Write("{0}: ", pi.GetCustomAttribute<PromptAttribute>().Prompt);
if (pi.PropertyType == typeof(int))
{
PromptInteger(p, pi);
}
else if (pi.PropertyType == typeof(string))
{
PromptString(p, pi);
} //add more types in this manner
}
return p;
}
private static void PromptString(Person p, PropertyInfo pi)
{
string userInput = Console.ReadLine();
pi.SetMethod.Invoke(p, new object[] { userInput });
}
private static void PromptInteger(Person p, PropertyInfo pi)
{
int userInput;
while (!int.TryParse(Console.ReadLine(), out userInput))
{
Console.Write("You have to enter an integer: ");
}
pi.SetMethod.Invoke(p, new object[] { userInput });
}
}
public class Person
{
[Prompt("Please enter the persons firstname")]
public string FirstName { get; set; }
[Prompt("Please enter the persons surname")]
public string SurName { get; set; }
[Prompt("Please enter the persons haircolor")]
public string HairColor { get; set; }
[Prompt("Please enter the persons eyecolor")]
public string EyeColor { get; set; }
[Prompt("Please enter the persons weight")]
public int Weight { get; set; }
[Prompt("Please enter the persons height")]
public int Height { get; set; }
[Prompt("Please enter the persons age")]
public int Age { get; set; }
}
public class PromptAttribute : Attribute
{
public string Prompt { get; private set; }
public PromptAttribute(string prompt)
{
Prompt = prompt;
}
}
}
Using the custom - attribute you could define the prompt. if you have more types just add more else ifs in the loop.
回答3:
A simple console app, using reflection, linq and a dictionary:
using statements:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
Your Class:
public class Person
{
public string firstname {get; set;}
public string surname { get; set; }
public string haircolor { get; set; }
public string eyecolor { get; set; }
public string weight { get; set; }
public string height { get; set; }
public string age { get; set; }
}
Console Application:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var per = new Person();
var perDict = new Dictionary<string, string>();
foreach (
var c in
per.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.ToDictionary(prop => prop.Name, prop => prop.GetValue(per,null))
)
{
Console.Write("Greetings, Please Enter Your Value for: " + c.Key + " ");
var answer = Console.ReadLine();
perDict.Add(c.Key, answer);
per.GetType().GetProperty(c.Key).SetValue(per,answer, null);
}
}
}
}
来源:https://stackoverflow.com/questions/29514987/c-sharp-calling-all-properties-for-each-loop