List outputs the namespace's name, instead of its values - c#

So, first of all, I am a beginner and this problem must be super simple, but I just don't find it. So the problem is, I have a small txt, containing fruits and its amounts:
Apple 26
Banana 55
Pear 12
Orange 32
Watermelon 81
Grapefruit 30
And I add these values in a list, but it outputs (in my opinion) the namespace's name. I guess this is some "property access" issue, but I don't know how to solve it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace practice
{
class Fruits
{
string fruit { get; set; }
int amount { get; set; }
public Fruits(string a, int b)
{
fruit = a;
amount = b;
}
}
class Program
{
static void Main(string[] args)
{
List<Fruits> data = new List<Fruits>();
StreamReader str_R = new StreamReader("list.txt");
while (!str_R.EndOfStream)
{
String[] line = str_R.ReadLine().Split(' ');
data.Add(new Fruits(line[0], Convert.ToInt32(line[1])));
}
foreach (var x in data)
{
Console.WriteLine(x);
}
Console.ReadKey();
}
}
}
Output:
practice.Fruits
practice.Fruits
practice.Fruits
practice.Fruits
practice.Fruits
practice.Fruits
I want the actual values of the list as output.

The base class of Fruits class is Object class, when you call an instance of a class by default it will return the ToString() method. the ToString() method of object returns the type of this object (the namespace). the ToString() method is Virtual (can be overridden by any class that inherits it) so you can override it:
class Fruits
{
string fruit { get; set; }
int amount { get; set; }
public Fruits(string a, int b)
{
fruit = a;
amount = b;
}
public override string ToString()
{
return string.Format("Fruit: {0} Ammount: {1}", fruit, amount);
}
}
Also, you can always do that:
foreach (var x in data)
{
Console.WriteLine(string.Format("Fruit: {0} Ammount: {1}", x.fruit, x.amount));
}

This is normal behavior. If given anything but a String, Console.WriteLine() will call ToString() on it.
Object.ToString() will simply output the class name, unless it is overridden.
You either need to override ToString() for Fruits:
public override string ToString(){
return fruit;
}
Or outpoint x.fruit and x.amount explicitly.
foreach (var x in data)
{
Console.WriteLine(x.fruit);
}

Related

Transform CSV input (1 field) to destination class (2 fields)

I'm writing my ClassMap which works for my first basic fields (including those with column name not matching class member).
But I have 2 fields which need a particular work
1) I have a color stored as string. I need some code which convert the input to 2 values and store each one in a specific member.
2) I have an ID which match CSV item ID (that's the father or mother ID). But I need to convert it to the ID in my database (so I have to write some code to match CSV_ID to DB_ID).
Is it possible to add this custom logic with CSVHelper ?
Thanks for help.
Vincent
As it seems, CSVHelper also supports the same type converter injection during class mapping.
https://joshclose.github.io/CsvHelper/examples/configuration/class-maps/type-conversion
By combining this with the support for mapping by alternate names,
https://joshclose.github.io/CsvHelper/examples/configuration/class-maps/mapping-by-alternate-names
Having a csv file like this:
Id,Name,Color
1,OGUZ OZGUL,#f0f0f0
2,VINCENT,#80A0C0
3,OZGUL OGUZ,#00A000
it is possible to achieve what's needed as follows:
using System;
using System.Globalization;
using System.IO;
using CsvHelper;
using CsvHelper.Configuration;
using CsvHelper.TypeConversion;
using System.Linq;
namespace console
{
public class Program
{
public class Foo
{
// Represents the database Id
public int Id { get; set; }
public string Name { get; set; }
// Represents a three character color code, like #FFF
public string Color3 { get; set; }
// Represents a six character color code like #FFFFFF
public string Color6 { get; set; }
}
// OK, we are not converting between types here, but who cares?
// CSVHelper certainly doesn't.
public class IdConverter : DefaultTypeConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
string csvId = text;
int databaseId = Convert.ToInt32(text) + 10000;
return databaseId;
}
public override string ConvertToString(object value, IWriterRow row, MemberMapData memberMapData)
{
return ((int)value - 10000).ToString();
}
}
// Again, we are changing the value as we wish, not the type.
public class Color3Converter : DefaultTypeConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
// format: #ffffff
return "#" + text[1] + text[3] + text[5];
}
public override string ConvertToString(object value, IWriterRow row, MemberMapData memberMapData)
{
// format: #fff
return "#" + ((string)value)[1] + "0" + ((string)value)[2] + "0" + ((string)value)[3] + "0";
}
}
// By combining a type converter and alternative name
// we achieve one CSV field value to be mapped to two properties
// of our class Foo
public sealed class FooMap : ClassMap<Foo>
{
public FooMap()
{
Map(m => m.Id).TypeConverter<IdConverter>();
Map(m => m.Name);
Map(m => m.Color3).TypeConverter<Color3Converter>().Name("Color");
Map(m => m.Color6).Name("Color");
}
}
static void Main(string[] args)
{
using (var reader = new StreamReader("data.csv"))
{
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
csv.Configuration.RegisterClassMap<FooMap>();
Foo[] records = csv.GetRecords<Foo>().ToArray();
foreach(Foo record in records)
{
Console.WriteLine
(
"Foo, Id: {0}, Name: {1}, Color3: {2}, Color6: {3}",
record.Id,
record.Name,
record.Color3,
record.Color6
);
}
}
}
}
}
}
The output of the program is:
Foo, Id: 10001, Name: OGUZ OZGUL, Color3: #fff, Color6: #f0f0f0
Foo, Id: 10002, Name: VINCENT, Color3: #8AC, Color6: #80A0C0
Foo, Id: 10003, Name: OZGUL OGUZ, Color3: #0A0, Color6: #00A000

Dynamically convert property to Type

Is it possible to simplify this logic, Is there generic way to do it.
The code finds marked attributes and parses it according to the attribute type.
Please suggest some way to optimize this code, all the data type of Product class will be string, I'm getting product input as xml directly converting serialized data to a class with decimal,int,float will not give proper error message, If there is list of item it throws error in xml we wont know which row has caused the error.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace TestSolution
{
public interface ICustomParser
{
bool Parse(string input);
}
public class DecimalParserAttribute : Attribute, ICustomParser
{
public bool Parse(string input)
{
if (input == null) return false;
decimal decimalValue;
return decimal.TryParse(input, out decimalValue);
}
}
public class intParserAttribute : Attribute, ICustomParser
{
public bool Parse(string input)
{
if (input == null) return false;
int intValue;
return int.TryParse(input, out intValue);
}
}
public class Product
{
[DecimalParser]
public string Weight { get; set; }
[intParser]
public string NoOfItems { get; set; }
[intParser]
public string GRodes { get; set; }
[intParser]
public string WRodes { get; set; }
}
class Program
{
static void Main(string[] args)
{
var sb = Validate(new Product() { NoOfItems = "1", GRodes = "4", Weight = "5", WRodes = "23" });
Console.WriteLine(sb);
sb = Validate(new Product() { NoOfItems = "1", GRodes = "4w", Weight = "5", WRodes = "23" });
Console.WriteLine(sb);
Console.ReadKey();
}
private static string Validate(Product product)
{
var sb = new StringBuilder();
foreach (var property in product.GetType().GetProperties())
{
var value = Convert.ToString(property.GetValue(product, null));
var sel = property.GetAttribute<ICustomParser>();
if (sel == null) continue;
var parserinstance = (ICustomParser)Activator.CreateInstance(sel.GetType());
if (parserinstance.Parse(value)) continue;
sb.AppendLine(string.Format("{0} Has invalid value", property.Name));
}
return sb.ToString();
}
}
public static class Extensions
{
public static T GetAttribute<T>(this PropertyInfo property)
{
return (T)property.GetCustomAttributes(false).Where(s => s is T).FirstOrDefault();
}
}
}
If you only have one type (Product), it probably isn't worth it - just write the validation code explicitly without all the fancy stuff. If, however, you have multiple types to inspect (perhaps known only at runtime):
It really depends how fast it needs to be. How often does this run? If it is periodic, then there isn't a vast amount to do - the main change would be to just cast the parser directly:
var parserInstance = (ICustomParser)sel;
(it already is the attribute type)
If it is critical path, then there is a lot you can do to beef it up, but you get into the realm of metaprogramming - which is essentially what most tools like serializers and ORMs do to reduce runtime reflection. If you're not familiar with hacking IL at runtime, I would recommend looking at a tool like "Sigil" (available on nuget) that makes it hard to get wrong (or at least: tells you what you've done wrong). Essentially, you can inspect the data structure and then emit the IL that matches what it would look like if you were doing it all in explicit code; for example, emitting IL that looks kinda like:
static readonly DecimalParserAttribute _decimal = new DecimalParserAttribute();
public static void Validate(Product product) {
var sb = new StringBuilder();
if(!_decimal.Parse(product.Weight)) {
sb.Append(...);
}
// ... etc
...,
}

Get access to my derived class members

I have several classes that inhabit from this class:
public abstract class Class1
{
private string _protocol;
private static List<Plus> _class1Objects;
public string Protocol
{
get { return _protocol; }
set { _protocol = value; }
}
public static List<Plus> Class1Objects
{
get { return _class1Objects; }
set { _class1Objects = value; }
}
}
And the derive class:
public class Class2 : Plus
{
public bool name;
public int id;
}
public Webmail(string name, int id)
{
if (Class1Objects == null)
Class1Objects = new List<class1>();
.....
Class1Objects.Add(this);
}
And after my list is full of Class1Objects:
for (int i = 0; i < Class1.Class1Objects.Count; i++)
{
if (Class1.Class1Objects[i].GetType() == typeof(Class2))
}
(Class2)Class1.Class1Objects[i].
}
}
Here after (Class2)Class1.Class1Objects[i]. i cannot see my Class2 memners
You need one additional paranthese:
((Class2)Class1.Class1Objects[i]).
At the moment it is read as the following:
(Class2)(Class1.Class1Objects[i].) //<= at the '.' it is still a class1
BUT as David said in his comment: If all are of type Class2 it should be a collection of that type and if not you should check the type, altogether with foreach:
foreach(var item in Class1.Class1Objects)
{
if(item is Class2)
((Class2)Class1.Class1Objects[i]).
}
It would be cleaner to use as:
for (int i = 0; i < Class1.Class1Objects.Count; i++)
{
var c2 = Class1.Class1Objects[i] as Class2;
if (c2!=null)
}
c2.<whatever was meant to come after the .>
}
}
You might also want to consider switching to foreach unless there's a specific reason you want to manually extract each element from the List, e.g. if you're actually storing new values back into the list.
The correct syntax would be:
((Class2)Class1.Class1Objects[i]).name;
Because in your case, when you type something like this:
(Class2)Class1.Class1Objects[i].name;
You try to access the member name of Class1.Class1Objects[i], and only after that you try to cast it to Class2.
Also, the whole loop would be much simpler if you used foreach:
using System.Linq;
foreach(Class2 c in Class1.Class1Objects.OfType<Class2>())
{
Console.WriteLine(c.name); // or whatever you need to do with it
}

How to sum two objects?

I want to do an application that pareses text. So far, I have a class called Result, that holds the value and type each part of an equation.
public enum ResultType
{
Int32,
Double,
Boolean,
Color,
DateTime,
String,
Undefined,
Void
}
public class Result
{
public object Value { get; set; }
public ResultType Type { get; set; }
}
Possible Result's could be:
5 : Int32
true : Boolean
DADACC : Color
"Hello World!" : String
10.0 : Double
13/11/1986 : DateTime
Now I want to sum/divide/pow/... two Results but I really don´t want to do all the work. In C#, you can mix them all together and get an answer.
var value = "Hello" + 2.0 + 4 + DateTime.Today; (value = "Hello2413/09/2011 12:00:00 a.m.")
Is there an easy way to handle this? Or do I have to figure out all combos by myself? I´m thinking about something like:
var Operator = "+"; // or "-","*","/","^","%"
var sum = DoTheCSharpOperation(Operator, ResultA.Value, ResultB.Value)
var sumResult = new Result(sum);
This sounds to me like a perfect application for the "dynamic" keyword:
using System;
using System.Diagnostics;
namespace ConsoleApplication33 {
public static class Program {
private static void Main() {
var result1=DoTheCSharpOperation(Operator.Plus, 1.2, 2.4);
var result2=DoTheCSharpOperation(Operator.Plus, "Hello", 2.4);
var result3=DoTheCSharpOperation(Operator.Minus, 5, 2);
Debug.WriteLine(result1); //a double with value 3.6
Debug.WriteLine(result2); //a string with value "Hello2.4"
Debug.WriteLine(result3); //an int with value 3
}
public enum Operator {
Plus,
Minus
}
public static object DoTheCSharpOperation(Operator op, dynamic a, dynamic b) {
switch(op) {
case Operator.Plus:
return a+b;
case Operator.Minus:
return a-b;
default:
throw new Exception("unknown operator "+op);
}
}
}
}

Compile Error CS0305

I'm new to C# programming and have hit a snag I cannot get past.
I'm getting this compile error:
CS0305: Using the generic type 'System.Collections.Generic.IEnumerable' reuires 1 type arguments
with this code;
class Program
{
static void Main(string[] args)
{
Car c = new Car();
c.PetName = "Frank";
c.Speed = 55;
c.colour = "Green";
Console.WriteLine("Name = : {0}", c.PetName);
c.DisplayStats();
Garage carLot = new Garage();
// Hand over each car in the collection
foreach (Car c in carLot)
{
Console.WriteLine("{0} is going {1} MPH",
c.PetName, c.CurrentSpeed);
}
Console.ReadLine();
}
class Car
{
//Automatic Properties
public string PetName { get; set; }
public int Speed { get; set; }
public string colour { get; set; }
public void DisplayStats()
{
Console.WriteLine("Car Name: {0}", PetName);
Console.WriteLine("Speed: {0}", Speed);
Console.WriteLine("Color: {0}", colour);
}
}
public class Garage
{
private Car[] CarArray = new Car[4];
// Fill with some car objects on startup.
public Garage()
{
carArray[0] = new Car("Rusty", 30);
carArray[1] = new Car("Clunker", 55);
carArray[2] = new Car("Zippy", 30);
carArray[3] = new Car("Fred", 30);
}
}
public IEnumerator GetEnumerator()
{
foreach (Car c in carArray)
{
yield return c;
}
}
}
How can I resolve this?
There are two variants of IEnumerable, the generic one (which is in the System.Collections.Generic namespace) accepts a type argument which specified the types of objects that the enumerable contains. The other one (contained in the System.Collections namespace) has no type argument and so exposes the type object - you appear to be declaring / using the non-generic variant, however are not using the System.Collections namespace.
I think the quick way to fix your particular compile error is to put the following at the top of your source code file:
using System.Collections;
Alternatively you can instead use the Generic version (which you should try to do wherever possible as it is type safe) by specifying type parameters when you declare IEnumerable, like this:
IEnumerable<Car>
IEnumerator<Car>
You might also want to read An Introduction to C# Generics
You also seem to have a few more errors than that, but these seem like they might be from problems copying and pasting the source (specifically Garage does not implement IEnumerable, either the generic or non-generic version, and GetEnumerator is on the Program class, not the Garage class).
You have more errors than just that. But specifically for that error, you're looping over Garage in a foreach, but that class does not expose an enumerator, mainly because the method GetEnumerator is actually outside of the class. Move the method inside Garage and then you'll be able to get all the way to scene of the next crash.
Actually, for that error, you need using System.Collections; and then you need to move the GetEnumerator method. Like I said, you have tons of errors in this code.
You have a lot of typos. As others have said, your specific answer is you need to add ": IEnumerable" to your class Garage statement.
Here is the code fixed enough to compile cleanly:
class Program
{
static void Main (string[] args)
{
Car c = new Car ("Frank", 55);
c.colour = "Green";
Console.WriteLine ("Name = : {0}", c.PetName);
c.DisplayStats ();
Garage carLot = new Garage ();
// Hand over each car in the collection
foreach (Car ch in carLot) {
Console.WriteLine ("{0} is going {1} MPH", ch.PetName, ch.Speed);
}
Console.ReadLine ();
}
class Car
{
//Automatic Properties
public string PetName { get; set; }
public int Speed { get; set; }
public string colour { get; set; }
public void DisplayStats ()
{
Console.WriteLine ("Car Name: {0}", PetName);
Console.WriteLine ("Speed: {0}", Speed);
Console.WriteLine ("Color: {0}", colour);
}
public Car(string petname, int speed) { PetName = petname; Speed = speed; }
}
public class Garage : IEnumerable
{
private Car[] carArray = new Car[4];
// Fill with some car objects on startup.
public Garage ()
{
carArray[0] = new Car ("Rusty", 30);
carArray[1] = new Car ("Clunker", 55);
carArray[2] = new Car ("Zippy", 30);
carArray[3] = new Car ("Fred", 30);
}
public IEnumerator GetEnumerator ()
{
foreach (Car c in carArray) {
yield return c;
}
}
}
}

Categories

Resources