Why I can't create object instance? - c#

I need add objects to list, but I can't understand how to do it correctly.
Every new object I get from console.
How to fix it?
My try:
namespace ExampleCars
{
public class Car
{
public string name;
public int speed;
public Car(string name, int speed)
{
this.name = name;
this.speed = speed;
}
}
class Program
{
static void Main(string[] args)
{
string name;
int speed, elements;
List<Object> cars = new List<Object>();
elements = Convert.ToInt32(Console.ReadLine());
if (elements > 0)
{
for (int i = 0; i < n; i++)
{
name = Convert.ToString(Console.ReadLine());
speed = Convert.ToInt32(Console.ReadLine());
Car newCar = new Car(name, speed);
cars.Add(newCar);
}
}
foreach (var oneCar in cars)
Console.WriteLine(oneCar);
}
}
}
In console I get this (elements == 1):
ExampleCars.Car

First of all, it would be better to create a List of Cars, instead of list of Objects. So change this:
List<Object> cars = new List<Object>();
To this:
List<Car> cars = new List<Car>();
Also it would be great, if you use properties instead of fields. And finally as the solution for your question, and based on what you need to show in your last Console.Writeline method, you can override the ToString method. Your class should be something like this:
public class Car
{
public string Name { get; set; }
public int Speed { get; set; }
public Car(string name, int speed)
{
Name = name;
Speed = speed;
}
public override string ToString()
{
return $"Name = {Name}, Speed = {Speed} ";
}
}
And if you are using the older versions of C#:
return String.Format("Name = {0}, Speed = {1}", Name, Speed);
The $ is called String Interpolation and is available from C#6+. I have provided an equivalent of it using String.Format that is available in older versions of C#.

when you write your Car object in the console, Car.ToString method call in background.
Object.ToString is the major formatting method in the .NET Framework.
It converts an object to its string representation so that it is
suitable for display. Default implementations of the Object.ToString
method return the fully qualified name of the object's type.
Object.ToString Method
if you want to change default string presentation of your object, you have to override the method.
public class Car
{
public string name;
public int speed;
public Car(string name, int speed)
{
this.name = name;
this.speed = speed;
}
public override string ToString()
{
return $"{name} {speed}";
}
}

Console.WriteLine, is responsible of printing text.
In case of Console.WriteLine(string) is actually returns the string value;
In any other case, it tries to convert the value into a string by invoking the instance object .ToString() method.
Any type in C# inherits from System.Object, and thus, it has the .ToString() method.
By using Inheritance, many types override the actual inherited method and implement their perception of what their value should look like as a string.
This can be easily done, by using method overriding and apply your own logic.
Example taken from MSDN
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return "Person: " + Name + " " + Age;
}
}
Test code
Person person = new Person { Name = "John", Age = 12 };
Console.WriteLine(person);
// Output:
// Person: John 12
So you may ask, why do i get ExampleCars.Car ? you're getting it, because you didn't implement your own representation of the object .ToString method. Thus, the System.Object implementation is to actually return the instance type as string, which is exactly what you're getting.
System.Object.ToString() Source code.
public virtual String ToString()
{
return GetType().ToString();
}
System.Int32 implement by changing the value of 1 to "1"
While other type can implement their own. e.g: new DateTime(2018, 12, 31) can return "12/31/2018"

Related

How to randomly pick value from a list in Unity3D?

Suppose I have a list of Robot class [List< Robot> myList=new List< Robot>()]. Each Robot has a name and id depending on its colour. Now randomly pick values from the list and give an output of how many Robots of each colour are there on your list.
(N.B. Consider you have only 3 colored Robot[Yellow,green, red])
my code:
public class Test : MonoBehaviour
{
private void Start()
{
List<Robot> myList = new List<Robot>();
List<string> robotList = new List<string>();
robotList.Add("yellow");
robotList.Add("green");
robotList.Add("red");
int someNum = Random.Range(0, robotList.Count);
string robotNumber = robotList[someNum];
robotList.RemoveAt(someNum);
Robot robot;
int id = 0;
robot = new Robot(robotNumber, id);
Debug.Log(robot);
id++;
}
}
public class Robot
{
public string name;
public int id;
public Robot(string name, int id)
{
this.name = name;
this.id = id;
}
}
but this not work maybe.. actually I don't understand what actually my output is...
Not sure to really understand what you're asking for: if it's only about the meaning of the Debug.Log(robot); output, check for #Smartis answer as it answers it perfectly :)
Otherwise, I feel like you wanted to populate a List<Robot> with random picked names. In this case you need to use a loop: Start() method is only called once on start (as its name suggest). If you need to populate a list with random picked colors/names and then display how many of each colors/names are in the list you can do it as follow:
public class Test : MonoBehaviour
{
private void Start()
{
List<Robot> robotsList = new List<Robot>();
List<string> namesList = new List<string>();
namesList.Add("yellow");
namesList.Add("green");
namesList.Add("red");
PopulateRobotsList();
DisplayRobotsListContent();
}
private void PopulateRobotsList()
{
for(int id = 0; id < 100; id++)
{
string robotName = namesList[Random.Range(0, namesList.Count)];
robotsList.Add(new Robot(robotName, id));
//Debug.Log(robotsList[robotsList.Count - 1]);
}
}
private void DisplayRobotsListContent()
{
int[] robotsNamesCount = new int[namesList.Count];
for (int i = 0; i < robotsList.Count; i++)
{
robotsNamesCount[namesList.IndexOf(robotsList[i].name)] += 1;
}
for (int i = 0; i < namesList.Count; i++)
{
Debug.Log("Robot(s) named \"" + namesList[i] + "\" : " + robotsNamesCount[i]);
}
}
}
public class Robot
{
public string name;
public int id;
public Robot(string name, int id)
{
this.name = name;
this.id = id;
}
}
Please note I changed some variable names as I found it really hard to understand with the one you provided (ex: robotsList to store the potential colors/names of the robots is a weird choice of name :) ).
Hope this helps,
Your random pick works fine (even when your code is a little bit confusing). I guess your problem is, you don't understand the output of Debug.Log(robot);.
actually I don't understand what actually my output is... - OP
What does Debug.Log() print?
According to the Unity3D Documentation for this function will converted the given object to be to string representation for display. This means simply the return value of ToString() method on your Object will printed.
So let's have look at the Object.ToString() method and it's behavior in the MSDN Documentation.
Default implementations of the Object.ToString method return the fully qualified name of the object's type. - MSDN
So, your output in the Unity Log will be the Type Definition of your object.
Now, how to get useful information?
Just override the default ToString() method of your Robot class to something like this:
public class Robot
{
public string name;
public int id;
public Robot(string name, int id)
{
this.name = name;
this.id = id;
}
// Here start's the magic!
public override string ToString()
{
return string.Format("Robot -> Id:'{0}' Name:'{1}'", id, name);
}
}

Returning string and int from same method

public static int getInfo(string info)
{
string inputValue;
int infor;
Console.WriteLine("Information of the employee: {0}", info);
inputValue = Console.ReadLine();
infor = int.Parse(inputValue);
return infor;
}
In the above code, how can I get the name(string) and salary(int) of a person? Specifications are that I need to call the method twice for the information retrieval.
You can pass it separately or better if you create a class which holds of info and the salary
public static int getInfo(string info,int salary)
or create a class,
public class MyInfo
{
public int info { get; set; }
public int salary { get; set; }
}
and the method signature goes as,
public static int getInfo(MyInfo info)
If you want to return both string and int , better to change the method signature as of type class MyInfo
public static MyInfo getInfo(MyInfo info)
You could make it return a tuple with both values like this:
internal Tuple<int, string> GetBoth(string info)
{
string inputValue;
int infor;
Console.WriteLine("Information of the employee: {0}", info);
inputValue = Console.ReadLine();
infor = int.Parse(inputValue);
return new Tuple<int, string>( infor, inputValue );
}
internal void MethodImCallingItFrom()
{
var result = GetBoth( "something" );
int theInt = result.Item1;
string theString = result.Item2;
}
For returning multiple values from a method we can use Tuples or (DataType, DataType,..).
Tuples are readonly. As a result assigning values is possible only via constructor at the time of declaration.
Below example is using multiple data types as return type. Which is both read and write enabled.
public (string, int) Method()
{
(string, int) employee;
employee.Item1="test";
employee.Item2=40;
return employee;
}
You can call the above method in your main code, as shown below:
static void Main(string[] args)
{
(string name,int age) EmpDetails = new Program().Method();
string empName= EmpDetails.name;
int empAge = EmpDetails.age;
//Not possible with Tuple<string,int>
EmpDetails.name = "New Name";
EmpDetails.age = 41;
}
However, the best practice is to use class with properties, as mentioned in above answers.
public static void Main(string[] args)
{
string eName, totalSales;
double gPay, tots, fed, sec, ret, tdec,thome;
instructions();
eName = getInfo("Name");
totalSales = getInfo("TotalSales");
tots = double.Parse(totalSales);
gPay = totalGpay(tots);
}
public static string getInfo(string info)
{
string inputValue;
Console.WriteLine("Information of the employee: {0}", info);
inputValue = Console.ReadLine();
return inputValue;
}
This is what was required. Could have done with other tricks mentioned by you guys. Anyway thank you.
Why dont you just return a String array with a size of 2? at the first (array[0]) there is the string and at the second (array[0]) there is the int...
public static string[] GetInfo (string info)
I hope I understood your question right ^^
you need to create a person class and read name and salary
public class Person
{
public string Name {get; set;}
public decimal Salary {get; set;}
}
and your function will be:
public static Person getInfo(string info)
{
string inputName;
string inputSalary;
Console.WriteLine("Information of the employee: {0}", info);
Console.WriteLine("Name:");
inputName = Console.ReadLine();
Console.WriteLine("Salary:");
inputSalary = Console.ReadLine();
Person person = new Person();
person.Name = inputName;
person.Salary = int.Parse(inputSalary);
return person;
}
If you want one method to return different types of information, then I would use generics:
public static T GetInfo<T>(string name);
// This can be called as following:
string name = GetInfo<string>("name");
int salary = GetInfo<int>("salary");
There's one problem, though: Console.ReadLine returns a string, while our method could return any type. How can it convert a string to its 'target' type? You could check T and write custom logic for all types you want to support, but that's cumbersome and brittle. A better solution is to let the caller pass in a little function that knows how to transform a string into a specific type:
public static T GetInfo<T>(string name, Func<string, T> convert);
// This can be called as following:
string name = GetInfo<string>("name", s => s);
int salary = GetInfo<int>("salary", int.Parse);
Now how do you implement that method?
public static T GetInfo<T>(string name, Func<string, T> convert)
{
Console.WriteLine("Please enter " + name);
string input = Console.ReadLine();
return convert(input);
}
A few notes:
Type parameters are often just named T, but I find it useful to give them more descriptive names, such as TInfo.
The <string> and <int> parts can be left out in the second example, because the compiler has sufficient information to infer their types.
I've left our error handling to keep the examples short and simple. In production code, you'll want to come up with a strategy to handle invalid input, though.

C# does altering a returned class object change the original state?

Assume I have the following class structure:
public class spaList
{
private List<customerItemFulfillment> customers;
public customerItemFulfillment addNewCustomer(
string customerNumber, string customerName)
{
customers.Add(new customerItemFulfillment(customerNumber, customerName));
return customers[customers.Count - 1];
//Would running .addItem() on this returned object affect the object in the list?
}
}
public class customerItemFulfillment
{
public string customerNumber { get; }
public string customerName { get; }
public List<itemFulfillment> fulfillmentItems { get; }
public void addItem(string itemNumber, double rebateAmount,
double fulfillmentPercent)
{
fulfillmentItems.Add(new itemFulfillment(itemNumber,
rebateAmount, fulfillmentPercent));
}
public customerItemFulfillment(string customerNumber, string customerName)
{
this.customerNumber = customerNumber;
this.customerName = customerName;
}
}
If I did something like:
spaList spaListings = new SpaList();
customerItemFulfillment newCustomer = spaListings.addNewCustomer(
"customer name", "customer number");
newCustomer.addItem("item number", 25.00, 8.0);
Does that change the customerItemFulfillment object in spaList.customers or is it just a copy of that object?
ie. would I later be able to do something like - spaListings.customers[0].fulfillmentItems[0] and have that be the item that I added earlier?
An object is a reference type. That means that the object reference is returned from the method, not a copy of the object. So yes, you are changing the original item. If you do this, you might end up with an invalid state of your customers list.
One option is to return a copy of the object. The easiest way to do this is by cloning the class and its properties using an implementation of ICloneable.

How to Display my object properly if it has a few parameters through linkedlist

i'm kind of new to C# and i need some help regarding my assignment.
First off, i have to display a linkedlist containing an Object called Parcel and that Parcel
contains a few parameters int id, string name, int weight. When try to call a function to display whatever is inside the linkedlist, i get an error.
here is my DisplayInventory() function :
public void DisplayInventory()
{
for (Node j = head; j != null; j = j.Link )
{
Console.WriteLine(j.Data);
}
}
Here is my parcel class :
class Parcel
private int id;
private String customerName;
private int weight;
public Parcel(int id, String customerName, int weight)
{
this.id = id;
this.customerName = customerName;
this.weight = weight;
}
public int ID
{
get { return id; }
set { id = value; }
}
public String CustomerName
{
get { return customerName; }
set { customerName = value; }
}
public int Weight
{
get { return weight; }
set { weight = value; }
}
}
And here is my Node Class :
class Node
{
private object data;
public object Data
{
get { return data; }
set { data = value; }
}
private Node link;
internal Node Link
{
get { return link; }
set { link = value; }
}
public Node(object d)
{
this.data = d;
}
}
Everything runs fine except for my DisplayInventory() function found in my linkedlist.cs. It just displayed AppName.Parcel when i tried to print it out, i know i have to cast my j.data, but it doesn't work for me, any help? Thanks a lot.
You should print each property instead:
Console.WriteLine("Id: " + j.Data.Id.ToString());
Console.WriteLine("Name: " + j.Data.Name);
and so on.
You can call Console.WriteLine() for each field/property of your Parcel class or override it's ToString() method. It would look like that:
public class Parcel()
{
public override string ToString()
{
string str = ....// create here your string representation of Parcel
// if number of fileds is quite big use StringBuilder class
return str;
}
}
Console.WriteLine will call object.ToString() on your j.Data object which by default just returns the type name (Parcel).
I'm assuming DisplayInventory is inside the class which is implementing the linked list - in which case you should be able to refer to the properties of the class directly:
e.g.
Console.WriteLine(j.Id);
You could also override ToString on whatever j is (Parcel) by adding this to the source:
public override string ToString() { return this.Id.ToString(); }
Edit:
Ok in light of your update, you can just cast Node.Data (j.Data) to Parcel and access members directly:
for (Node j = head; j != null; j = j.Link )
{
// Cast using the as keyword - if the cast fails, parcel will be null, otherwise it will be the casted object
var parcel = j.Data as Parcel;
// Check if parcel is null, if not write some info
if(parcel != null)
{
Console.WriteLine(parcel.Id);
Console.WriteLine(parcel.CustomerName); // etc
}
}
Alternatively - just use j.Data.ToString() and ensure you have overridden the ToString member for Parcel
e.g. in Parcel.cs
// Override the ToString method. If you are using Visual Studio you should get a popup
// telling you which methods you can override after you type override then hit space
public override string ToString()
{
// string.format is one way of formatting the data, the tokens are replaced by the indexed arguments
return string.Format("{0} - {1}", Id, CustomerName);
}

How to create a simplified assignment or default property for a class in C#

This is minor, I know, but let's say that I have a class Character and a class Ability (mostly because that's what I'm working on). Class Character has six abilities (so typical D&D...). basically:
public class Character
{
public Character()
{
this.Str = new Ability("Strength", "Str");
this.Dex = new Ability("Dexterity", "Dex");
this.Con = new Ability("Constitution", "Con");
this.Int = new Ability("Intelligence", "Int");
this.Wis = new Ability("Wisdom", "Wis");
this.Cha = new Ability("Charisma", "Cha");
}
#region Abilities
public Ability Str { get; set; }
public Ability Dex { get; set; }
public Ability Con { get; set; }
public Ability Int { get; set; }
public Ability Wis { get; set; }
public Ability Cha { get; set; }
#endregion
}
and
public class Ability
{
public Ability()
{
Score = 10;
}
public Ability(string Name, string Abbr)
: this()
{
this.Name = Name;
this.Abbr = Abbr;
}
public string Name { get; set; }
public string Abbr { get; set; }
public int Score { get; set; }
public int Mod
{
get
{
return (Score - 10) / 2;
}
}
}
When actually using these ability properties in future code, I'd like to be able to default to just the score, like so:
//Conan hits someone
int damage = RollDice("2d6") + Conan.Str;
//evil sorcerer attack drains strength
Conan.Str = 0;
rather than:
//Conan hits someone
int damage = RollDie("2d6") + Conan.Str.Score;
//evil sorcerer attack drains strength
Conan.Str.Score = 0;
Now, the first case can be taken care of with an implicit conversion:
public static implicit operator int(Ability a)
{
return a.Score;
}
Can anybody help me with the reverse? Implicit conversion like this:
public static implicit operator Ability(int a)
{
return new Ability(){ Score = a };
}
will replace the entire attribute rather than just the score of the attribute—not the desired result...
The best you can do is increment the score by adding these methods to Ability.
public static Ability operator + (Ability lhs, int score)
{
lhs.Score += score;
return lhs;
}
public static Ability operator - (Ability lhs, int score)
{
lhs.Score -= score;
return lhs;
}
public static implicit operator int(Ability rhs)
{
return rhs.Score;
}
and using them like:
static void Main(string[] args)
{
Character evil = new Character(); //Str.Sccore=10
evil.Str += 10; //cast spell for Str.Sccore=20
evil.Str -= evil.Str; //death with Str.Sccore=0
}
First, keep your implicit conversion:
public static implicit operator Ability(int a)
{
return new Ability(){ Score = a };
}
Then in your character class: Add a private Ability attribute for str, and change the getter and the setter of the Str property as follows:
private Ability str;
public Ability Str
{
get
{
return this.str;
}
set
{
if (value.Name == "")
{
this.str.Score = value.Score;
}
else
{
this.str = value;
}
}
}
There you go :)
You could also use:
if(string.IsNullOrWhiteSpace(value.Name))
instead of
if (value.Name == "")
If you are compiling to .NET 4.0 version
EDIT: I gave you a solution that does exactly what you wanted to, but What ja72 wrote is also a good suggestion with operators + and -; you can add his solution to mine (or mine to him, whatever), it will work just fine. You will then be able to write:
Character Jax = new Character(); // Str.Score = 10
Character Conan = new Character(); // Str.Score = 10
Jax.Str = 2000; // Str.Score = 2000;
Conan.Str += 150; // Str.Score = 160
Another option is to replace the properties with delegates like this
public class Character
{
public Character()
{
...
}
#region Abilities
...
#endregion
public Func<int> Strength
{
get { return () => Str.Score; }
set { Str.Score = value(); }
}
}
and use it like this
Character evil = new Character(); //Str.Sccore=10
// fist spell hits
evil.Strength = () => 5; //set Str.Score=5
// second spell hits
evil.Strength = () => 0; //set Str.Score=5
if (evil.Strength() == 0)
{
// dead
}
Perhaps you could make Ability abstract and then derive new classes from Ability for each of the sub-classes: Strength, ...
The constructor for the Strength class would look something like this:
public Strength () : base ("Strength", "Str") { ...}
Now the ability properties off a Character would be strongly typed and the implicit conversions could turn a value like 5 into a Strength object with a value of 5. This would also prevent you from accidentally storing a Dexterity in a Strength property, for example.
[Assuming the name and abbreviations are in fact fixed for all objects of that type.]

Categories