C# properties and "tostring" method - c#

I was trying to understand properties better and I came across this page with this example:
https://www.tutorialspoint.com/csharp/csharp_properties.htm
using System;
namespace tutorialspoint {
class Student {
private string code = "N.A";
private string name = "not known";
private int age = 0;
// Declare a Code property of type string:
public string Code {
get {
return code;
}
set {
code = value;
}
}
// Declare a Name property of type string:
public string Name {
get {
return name;
}
set {
name = value;
}
}
// Declare a Age property of type int:
public int Age {
get {
return age;
}
set {
age = value;
}
}
public override string ToString() {
return "Code = " + Code +", Name = " + Name + ", Age = " + Age;
}
}
class ExampleDemo {
public static void Main() {
// Create a new Student object:
Student s = new Student();
// Setting code, name and the age of the student
s.Code = "001";
s.Name = "Zara";
s.Age = 9;
Console.WriteLine("Student Info: {0}", s);
//let us increase age
s.Age += 1;
Console.WriteLine("Student Info: {0}", s);
Console.ReadKey();
}
}
}
output: Student Info: Code = 001, Name = Zara, Age = 9
I don't understand how the first example is able to output the whole line written in the class "student". In the main method, we are using "s" which is an object created in the class "exampledemo". How is it able to call a method from another class?
I guess it's something related to inheritance and polymorphism (I googled the override keyword) but it seems to me that the two classes are indipendent and not a subclass of the other.
I'm a total beginner at programming and probably quite confused.

s is of type Student (as declared on the first line of Main()). Therefore one can call a method on the object to modify it or print it. When you do s.Name = "Zara"; you are already calling a method on Student to update it (technically, a method and a property are the same, they only differ by syntax).
The line Console.WriteLine("Student Info: {0}", s); is actually the same as Console.WriteLine("Student Info: " + s.ToString());. The compiler allows writing this in a shorter form, but internally the same thing happens.

Let me show a real life example.
You have a sketch of your dream bicycle. Your bicycle exists only in sketch. This is a class.
Then you are going to garage and building your bicycle from the sketch. This process can be called like creation of object
of bicycle at factory from your sketch.
According to your example, class is Student.
You are creating an object by the following line:
Student s = new Student();
Object takes space in memory. How can we read values of objects from memory? By using object reference.
s is an object reference to the newly created object type of Student.
How is it able to call a method from another class?
s is an object reference to the newly created object type of Student. So it can call any public method of this object.
I was trying to understand properties
Properties are evolution of getter and setter methods. Looking for a short & simple example of getters/setters in C#
The compiler generates a pair of get and set methods for a property, plus a private backing field for an auto-implemented property.
Are C# properties actually Methods?

Related

Can I change this extension method to remove the "magic string"? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Finding the Variable Name passed to a Function in C#
The class below contains the field city.
I need to dynamically determine the field's name as it is typed in the class declaration
i.e. I need to get the string "city" from an instance of the object city.
I have tried to do this by examining its Type in DoSomething() but can't find it when examining the contents of the Type in the debugger.
Is it possible?
public class Person
{
public string city = "New York";
public Person()
{
}
public void DoSomething()
{
Type t = city.GetType();
string field_name = t.SomeUnkownFunction();
//would return the string "city" if it existed!
}
}
Some people in their answers below have asked me why I want to do this.
Here's why.
In my real world situation, there is a custom attribute above city.
[MyCustomAttribute("param1", "param2", etc)]
public string city = "New York";
I need this attribute in other code.
To get the attribute, I use reflection.
And in the reflection code I need to type the string "city"
MyCustomAttribute attr;
Type t = typeof(Person);
foreach (FieldInfo field in t.GetFields())
{
if (field.Name == "city")
{
//do stuff when we find the field that has the attribute we need
}
}
Now this isn't type safe.
If I changed the variable "city" to "workCity" in my field declaration in Person this line would fail unless I knew to update the string
if (field.Name == "workCity")
//I have to make this change in another file for this to still work, yuk!
{
}
So I am trying to find some way to pass the string to this code without physically typing it.
Yes, I could declare it as a string constant in Person (or something like that) but that would still be typing it twice.
Phew! That was tough to explain!!
Thanks
Thanks to all who answered this * a lot*. It sent me on a new path to better understand lambda expressions. And it created a new question.
Maybe you need this. Works fine.
I found this here.
static void Main(string[] args)
{
var domain = "matrix";
Check(() => domain);
Console.ReadLine();
}
static void Check<T>(Expression<Func<T>> expr)
{
var body = ((MemberExpression)expr.Body);
Console.WriteLine("Name is: {0}", body.Member.Name);
Console.WriteLine("Value is: {0}", ((FieldInfo)body.Member)
.GetValue(((ConstantExpression)body.Expression).Value));
}
Output will be:
Name is: 'domain'
Value is: 'matrix'
I know this is old question, but I was trying to achieve the same and google sent me here. After many hours I finally found a way. I hope somebody else will find this useful.
There are actually more ways to accomplish this:
static void Main(string[] args)
{
GetName(new { var1 });
GetName2(() => var1);
GetName3(() => var1);
}
static string GetName<T>(T item) where T : class
{
return typeof(T).GetProperties()[0].Name;
}
static string GetName2<T>(Expression<Func<T>> expr)
{
return ((MemberExpression)expr.Body).Member.Name;
}
static string GetName3<T>(Func<T> expr)
{
return expr.Target.GetType().Module.ResolveField(BitConverter.ToInt32(expr.Method.GetMethodBody().GetILAsByteArray(), 2)).Name;
}
The first is fastest. The last 2 are approx 20 times slower than the 1st one.
http://abdullin.com/journal/2008/12/13/how-to-find-out-variable-or-parameter-name-in-c.html
city in this case is an instance of type string. When you call .GetType() you return the actual string type, which has no knowledge at all of your particular city instance.
I'm having a hard time seeing why you can't just type "city" in the code as a string literal here, if that's what you need. Perhaps it would help if you shared what you want to use this value for and in what circumstances you will call your DoSomething() function.
At the moment, my best guess is that what you really want to do is reflect the entire Person class to get a list of the fields in that class:
public void DoSomething()
{
MemberInfo[] members = this.GetType().GetMembers();
// now you can do whatever you want with each of the members,
// including checking their .Name properties.
}
Okay, based on your edit I have some more for you.
You can find the name of fields that are decorated with your attribute at run-time like this:
Type t = typeof(Person);
foreach (MemberInfo member in t.GetMembers()
.Where(m =>
m.GetCustomAttributes(typeof(MyCustomAttribute)).Any() ) )
{
// "member" is a MemberInfo object for a Peson member that is
// decorated with your attribute
}
You can also use binding flags in the first GetMembers() call to limit it to just fields, if you want.
You mentioned "i.e. I need to get the string "city" from an instance of the object city."
Are you looking to get the field name from the value of the field.
For example:If there are 2 Person object one with city "New York" and the other with city "London", are you looking for the function to return "city". Is this what you mean by dynamic?
With your current design you will always need to compare the name of the field from the FieldInfo against a string.
What if you instead decouple this so that you hold the identifier to use for comparison purposes during reflection as part of the attribute.
Something like this:
public enum ReflectionFields
{
CITY = 0,
STATE,
ZIP,
COUNTRY
}
[AttributeUsage(AttributeTargets.Field,AllowMultiple=false)]
public class CustomFieldAttr : Attribute
{
public ReflectionFields Field { get; private set; }
public string MiscInfo { get; private set; }
public CustomFieldAttr(ReflectionFields field, string miscInfo)
{
Field = field;
MiscInfo = miscInfo;
}
}
public class Person
{
[CustomFieldAttr(ReflectionFields.CITY, "This is the primary city")]
public string _city = "New York";
public Person()
{
}
public Person(string city)
{
_city = city;
}
}
public static class AttributeReader<T> where T:class
{
public static void Read(T t)
{
//get all fields which have the "CustomFieldAttribute applied to it"
var fields = t.GetType().GetFields().Where(f => f.GetCustomAttributes(typeof(CustomFieldAttr), true).Length == 1);
foreach (var field in fields)
{
var attr = field.GetCustomAttributes(typeof(CustomFieldAttr), true).First() as CustomFieldAttr;
if (attr.Field == ReflectionFields.CITY)
{
//You have the field and you know its the City,do whatever processing you need.
Console.WriteLine(field.Name);
}
}
}
}
public class Program
{
public static void Main(string[] args)
{
PPerson p1 = new PPerson("NewYork");
PPerson p2 = new PPerson("London");
AttributeReader<PPerson>.Read(p1);
AttributeReader<PPerson>.Read(p2);
}
}
You can now freely rename _city field of Person to something else and your calling code will still work since the code using reflection is trying to identify the field using the ReflectionFields enum value set as part of initialization of the attribute set on the field.
Yes its possible !!!
Try this out...
public string DoSomething(object city)
{
return city.GetType().GetProperty("Name",typeof(string)).GetValue(city,null);
}
Two things here.
Number one, as someone above pointed out, you're getting the Type for string, not for Person. So typeof(Person).GetMembers() will get you the list of members.
Number two, and more importantly, it looks like you're misunderstanding the purpose of attributes. In general attributes are used to mark a member for specific processing or to add additional information. Here you're using the name to indicate what processing you want, and the attribute to specify parameters, which is mixing of metaphors, or something.
Abhijeet's answer is more appropriate, you mark the field as a city field, then do what you like with it. Where I disagree is that I would use different attribute classes, rather than an enumeration.
Something like:
public class MyAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Field)]
public class MyCityAttribute : MyAttribute
{
}
[AttributeUsage(AttributeTargets.Field]
public class MyNameAttribute: MyAttribute
{
}
public class Person
{
[MyCity]
public string city = "New York";
[MyCity]
public string workCity = "Chicago";
[MyName]
public string fullName = "John Doe";
public Person()
{
}
public void DoSomething()
{
Type t = typeof(Person);
FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach (var field in fields)
{
MyAttribute[] attributes = field.GetCustomAttributes(typeof(MyAttribute));
if (attributes.Count > 0)
{
if (attributes[0] is MyCityAttribute)
{
//Dosomething for city
break;
}
if (attributes[0] is MyNameAttribute)
{
//Dosomething for names
break;
}
}
}
}
}
This would allow you to use different parameters for MyCity vs MyName that would make more sense in the context of processing each.
I think with your 'yuk' comment above, you hit the nail on the head. That you would have to change a string constant if you rename your variable is an indicator that you're doing something wrong.
t.GetField("city", BindingFlags.Public | BindingFlags.Instance);
or you can call GetFields() to get all fields
You need to call get type on the class Person. The iterate the fields of the class as in the answer below
This is not possible (I think it actually is but involes several hacks and using lambdas). If you want to store attributes about a Person and be able to get the name of the attribute easily, I suggest using a Dictionary<TKey, TValue> from the System.Collections.Generic namespace.
And you can always make public properties that wrap the dictionary.
public class Person
{
Dictionary<string, string> attributes = new Dictionary<string, string();
public string City
{
get { return attributes["city"]; }
set { attributes["city"] = value; }
}
public Person()
{
City = "New York";
}
}
And you can get a list of all attributes with attributes.Keys.
Have a look at this post as it looks similar to what you're trying to do:
Finding the variable name passed to a function
(especially Konrad Rudolph's answer) Another approach could be to just add "city" as one of the parameters in the attribute and fish that out later.
You are already looping through the collection of FieldInfo objects. Look for your attribute on those and when you find the FieldInfo that contains your attribute, you have the one you want. Then call .Name on it.
system.reflection.fieldinfo.attributes

How to create a method that takes a generic class as a parameter

I've been searching S.O and elsewhere for an answer to this question, and I can't find one that is helping me understand my problem. I'm new to C#, so that might be part of the issue.
I'm trying to get a handle on how to pass a class (or a copy of one) as a parameter to a method. However, I want this method to accept any class I pass it, not a specific one.
So for instance:
class Person
{
public string Name{ get;set; }
}
class Bob : Person
{
public Bob(){ Name = "Bob"; }
}
class Fred : Person
{
public Fred(){ Name = "Fred"; }
}
Fred aFred = new Fred();
Bob aBob = new Bob();
// below is where I need the help, I don't know the syntax for what I'm trying to do.
SayName(aBob,aFred);
static public void SayName(person1,person2)
{
Console.WriteLine(person1.Name + ", " +person2.Name) // I'd like this to output "Bob, Fred"
}
Okay, I know that above syntax isn't correct insofar as passing those classes as parameters or in accepting them as arguments for the method, but I'm hoping that you can see what I'm trying to do. I'd like to be able to pass any class deriving from Person to the SayName method, and have it output whatever its name happens to be.
Thanks in advance, any help is appreciated.
Is there a way to do this?
Just pass them as Person:
static public void SayName(Person person1, Person person2)
{
Console.WriteLine(person1.Name + ", " +person2.Name) // I'd like this to output "Bob, Fred"
}
Type is not declared as parameters in SayName, seems to be a misunderstanding in understanding how to pass parameters. Use Person type for both parameters say person1 and person 2 the code will run
public static void SayName(Person person1, Person person2)
{
Console.WriteLine(person1.Name + ", " +person2.Name)
}

mismatch in member variables in C# class

I am new to C#, and writing a piece of code to do some exercises. What surprises me is that I can use undefined member variables in a C# class as if they had been defined. Below is my code. In class Person, I only defined "myName" and "myAge," but I can use the member variables "Name" and "Age" without any issue. The code can be compiled and the executable can be run. Can someone tell me why I can use "Name" and "Age" without defining them? Many thanks,
C# code
======================================
using System;
namespace prj01
{
class Person
{
private string myName = "N/A";
private int myAge = 0;
public string Name
{
get
{
return myName;
}
set
{
myName = value;
}
}
public int Age
{
get
{
return myAge;
}
set
{
myAge = value;
}
}
public override string ToString()
{
return "Name = " + Name + ", Age = " + Age;
}
}
class Program
{
static void Main(string[] args)
{
// property
Console.WriteLine("Simple Properties");
Person person01 = new Person();
Console.WriteLine("Person details - {0}", person01);
person01.Name = "Joe"; // Why can I use "Name"?
person01.Age = 99; // Why is "Age" accessible and usable?
Console.WriteLine("Person details - {0}", person01);
Console.ReadLine();
}
}
}
======================================
You did define them. Right here:
public string Name
{
get
{
return myName;
}
set
{
myName = value;
}
}
public int Age
{
get
{
return myAge;
}
set
{
myAge = value;
}
}
These are called "properties" in .NET classes. In your current code, they're essentially "pass-through" properties which do nothing but delegate access to the member variables. They compile into getter and setter methods wrapping those member variables.
Name and Age are public properties, these are used by code external to the class to send in data, that is, to modify the private variables. If you change the public beside Name to private, you won't be able to use that property because of the protection level: What is the difference between Public, Private, Protected, and Nothing?
.Net classes expose 2 types of data members
1>Fields :
in your example they are myName and myAge, since they are private you can only use them within your class members.
2> Properties
In you class they are Name and Age.
Since they are public they can be accessed within and outside your class.
With properties you can getters and/or setters.
getters enable you to read Value from a property eg :
Person person01 = new Person();
int xyz = person01.Age; // it is internally calling person01.Age.get();
and setters enable setting value for the property ie
Person person01 = new Person();
person01.Age = 2;// this is internally calling person01.Age.set(2);
Hope this clarifies.

Changing objects value in foreach loop?

In one place i am using the list of string in that case the i am able to change the value of the string as code given below,
foreach(string item in itemlist.ToList())
{
item = someValue; //I am able to do this
}
But for object of class i am not able to alter the members value of the object the code is as below,
public class StudentDTO
{
string name;
int rollNo;
}
studentDTOList=GetDataFromDatabase();
foreach(StudentDTO student in studentDTOList.ToList())
{
student = ChangeName(student); //Not working
}
private StudentDTO ChangeName(StudentDTO studentDTO)
{
studentDTO.name = SomeName;
return studentDTO;
}
Error is : Can not assign because it's iteration variable
You cannot change the iteration variable of a foreach-loop, but you can change members of the iteration variable. Therefore change the ChangeName method to
private void ChangeName(StudentDTO studentDTO)
{
studentDTO.name = SomeName;
}
Note that studentDTO is a reference type. Therefore there is no need to return the changed student. What the ChangeName method gets, is not a copy of the student but a reference to the unique student object. The iteration variable and the studentDTOList both reference the same student object as does the studentDTO parameter of the method.
And change the loop to
foreach(StudentDTO student in studentDTOList)
{
ChangeName(student);
}
However, methods like ChangeName are unusual. The way to go is to encapsulate the field in a property
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
You can then change the loop to
foreach(StudentDTO student in studentDTOList)
{
student.Name = SomeName;
}
EDIT
In a comment you say that you have to change many fields. In that case it would be okay to have a method UpdateStudent that would do all the changes; however I still would keep the properties.
If there is no additional logic in the properties besides passing through a value, you can replace them by the handy auto-implemented properties.
public string Name { get; set; }
In that case you would have to drop the field name.
You're not actually changing the object that you're referring to anyway, so you can just use:
foreach (StudentDTO student in studentDTOList)
{
student.name = SomeName;
}
Or still call a method:
foreach (StudentDTO student in studentDTOList)
{
ChangeStudent(student);
}
In both cases, the code doesn't change the value of the iteration variable (student) so it's okay.
But your original example doesn't compile anyway - an iteration variable introduced by a foreach loop is read-only.
Instead of Foreach, I used For loop, this way I also get the Index that is needed to be changed, Then I call a function, In which I pass the Data to be Changed as well as the index to be changed from:
for(int i = 0; i< myList.Count; i++)
{
if(mylist[i] == otherData)
{
//call the function
ChangeData(otherData, i);
}
}
public void ChangeData(DataType DataToChangeInto, int i)
{
mylist[i] = DataToChangeInto;
}

Polymorphism - exercise

Alright, so this is the exercise:
Define a class named student,
containing three grades of students.
The class will have a function that
calculates the grades average. Now,
define a class named student1 which
will be derived from student and will
add a function to calculate the sum of
the grades.In the Main program, define
a student variable and object of type
student1. Perform placement of the
object to variable and run the
function of student1.
Note: This is not homework, I'm learning this my own.
This is the code:
class Student
{
protected int grade1, grade2, grade3;
public Student(int grade1, int grade2, int grade3)
{
this.grade1 = grade1;
this.grade2 = grade2;
this.grade3 = grade3;
}
public double Average()
{
return (grade1 + grade2 + grade3) / 3;
}
}
class Student1 : Student
{
public Student1(int grade1, int grade2, int grade3)
: base(grade1, grade2, grade3)
{
}
public double Sum()
{
return grade1 + grade2 + grade3;
}
}
class Program
{
static void Main(string[] args)
{
}
}
I don't really know what to do in the main class, how do I perform this placement and also, I wanted to know what's the benefit of doing it, let me know if I have mistakes so far, thanks alot.
OK: I guess this is what they're looking for, although the english is a little ropey:
1) Declare student variable
Student s;
2) Declare Student1 object
Student1 s1 = new Student1(1,2,3);
3) Perform placement of object to variable:
s = s1;
4) Run the function (Note you'll have to cast s to Student1 type to access the Type specific function Sum)
Console.WriteLine(((Student1)s).Sum());
Maybe this is what it means.. although its really badly worded in my eyes.
In the Main program, define a student variable and object of type student1. Perform placement of the object to variable and run the function of student1.
static void Main(string[] args)
{
//define a student variable and object of type student1.
Student student = new Student1(100, 99, 98);
//Perform placement of the object to variable and run the function of student1
var sum = ((Student1)student ).Sum();
}
The primary flaw I see in your code from an OOP perspective is making Student1 extend from Student. When using inheritance, make sure it's a true extension (is a). You would be better served by making 1 student class and implementing the Sum and Average methods.
I think the following would be sufficient from an OOP perspective.
class Student
{
protected int grade1, grade2, grade3;
public Student(int grade1, int grade2, int grade3)
{
this.grade1 = grade1;
this.grade2 = grade2;
this.grade3 = grade3;
}
public double Average()
{
return (grade1 + grade2 + grade3) / 3;
}
public double Sum()
{
return grade1 + grade2 + grade3;
}
}
Following exactly what was described by the exercise:
// Define a student variable.
Student s;
// And object of type Student1.
Student1 s1 = new Student1(10, 5, 8);
// Perform placement of the object to variable.
s = s1;
// And run the function of Student1.
// But it makes no sense...
s1.Sum();
// Maybe the exercise wants it:
((Student1)s).Sum();
// Which makes no sense too, since is making an idiot cast.
// But for learning purposes, ok.
Well, I don't believe this exercise is taking any advantage of polymorphism in C#. I suggest you reading the link to see a real usage sample.

Categories