I have two classes named Person and Staff. Person class just keeps fields and properties. Staff class implements IEnumarable interface. What I want to do is to make this class enumarable. I will create an instance Staff class on form_Load and then iterate over it. But I think something is wrong here.
public Person this[int index]
{
get { return Staff[index]; }
set { Staff[index] = value; }
}
This is what I have so far. How can I fix this
public class Person
{
private int _age;
private string _name;
public int Age
{
get { return _age; }
set { _age = value; }
}
public string Name
{
get { return _name; }
set { _name = value; }
}
public Person(int age, string name)
{
_age = age;
_name = name;
}
}
public class Staff : IEnumerable
{
private List<Person> list;
public Person this[int index]
{
get { return Staff[index]; }
set { Staff[index] = value; }
}
public Staff(Person person)
{
list = new List<Person>();
list.Add(person);
}
public IEnumerator GetEnumerator()
{
for (int i = 0; i < list.Count; i++)
{
yield return list[i];
}
}
}
Syntax errors indeed. This would work though:
static void Main(string[] args)
{
var staff = new Staff();
staff.AddPerson(new Person(12, "John Doe"));
staff.AddPerson(new Person(12, "Jande Doe"));
foreach (var person in staff)
{
Console.WriteLine(person.Name);
}
Console.ReadLine();
}
}
public class Person
{
public int Age { get; private set; }
public string Name { get; private set; }
public Person(int age, string name)
{
Name = name;
Age = age;
}
}
public class Staff : IEnumerable<Person>
{
private List<Person> staff = new List<Person>();
public void AddPerson(Person p)
{
this.staff.Add(p);
}
public IEnumerator<Person> GetEnumerator()
{
return this.staff.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.staff.GetEnumerator();
}
}
I'm getting the impression that you want to enumerate the collection of persons through the staff class. You can do that by implementing IEnumerable and return the enumerator of the people list. So that's what I did.
I implemented IEnumerable to return a strongly typed enumerator and shortened some of your code. Hope it helps.
Related
I have a class with some private and public fields and properties.
[MessagePackObject(false)]
public class Person
{
[Key(1)]
public string Name { get; set; }
[IgnoreMember]
private int _age;
[Key(2)]
public int Age { get { return _age; } set { _age = value; } }
}
In some cases I don't need to serialize Age, I need to serialize only some fields (for example only Name). So I need 2 methods, to serialize all object and partial serialize. How can I organize it?
Answering to my own question.
The only solution I have found is to move Name to base class BasePerson. I will serialize object as BasePerson and then deserialize bytes to Person
[MessagePackObject(false)]
public class BasePerson
{
[Key(1)]
public string Name { get; set; }
}
[MessagePackObject(false)]
public class Person
{
[IgnoreMember]
private int _age;
[Key(2)]
public int Age { get { return _age; } set { _age = value; } }
}
Usage:
Person person = new Person()
{
Name = "Gor",
Age = 26
};
var serializedBytes = MessagepackSerializer.Serialize<BasePerson>(person);
// will give me person with `Name` "Gor" and `Age` 0 (default value of int)
var personWithoutAge = MessagepackSerializer.Deserialize<Person>(serializedBytes );
I am trying to learn OOP by creating a small program that reads a list of people and outputs only those who are older than 30 using two classes Person and PollParticipant. I am instantiating a new person from my person class and adding name and age:
Person person = new Person(name,age);, which are defined in a constructor, but when I do so it gives me an error that the name 'name' does not exist in the current context. My fields are set to public, so it should be able to access them, what am I doing wrong?
Here is my Person class:
namespace Poll_Opinion
{
public class Person
{
public string name;
public int age;
public Person(string name, int age)
{
this.name = Name;
this.age = Age;
}
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
public int Age
{
get
{
return this.age;
}
set
{
this.age = value;
}
}
}
}
My poll participants class:
namespace Poll_Opinion
{
class PollParticipant
{
public List<Person> pollParticipant;
public PollParticipant()
{
this.pollParticipant = new List<Person>();
}
public void AddMember(Person participant)
{
this.pollParticipant.Add(participant);
}
public Person ShowOlderMembers()
{
return this.pollParticipant.OrderByDescending(p => p.age).First();
}
}
}
And my Program.cs where I make the instantiation:
namespace Poll_Opinion
{
class Program
{
static void Main(string[] args)
{
PollParticipant pollparticipant = new PollParticipant();
int n = int.Parse(Console.ReadLine());
for (int i = 0; i < n; i++)
{
string[] input = Console.ReadLine().Split();
int age = int.Parse(input[i]);
Person person = new Person(name,age);
pollparticipant.AddMember(person);
}
}
}
}
You have two issues. The first is here:
Person person = new Person(name,age);
You try to pass name and age to the Person constructor but you have not instantiate them.
The second problem is in your constructor:
public Person(string name, int age)
{
// this.name = Name;
this.name = name;
// this.age = Age;
this.age = age;
}
You need to assign name parameter to this.name field, not Name property. In you case you assign this.name to this.name:
this.name = Name; // => where 'Name' get method return this.name
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
By the way, you don't need a public field name (that should be private) in this case. Just do:
public string Name { get; set; }
In C# the properties pratically already have an hidden private field.
name is not defined in your Main() function when you are creating the Person objects.
I'm working on an approach to have a collection that efficiently can search based on more than one property. The sample code of the approach:
class SampleCollection
{
Dictionary<Sample, Sample> _dictItems;
public SampleCollection()
{
_dictItems = new Dictionary<Sample, Sample>(new SampleEqualityComparer());
}
public Sample FindById(int id)
{
return _dictItems[new Sample(id, string.Empty)];
}
public Sample FindByName(string name)
{
return _dictItems[new Sample(-1, name)];
}
}
class Sample
{
public Sample(int id, string name)
{
Id = id;
Name = name;
}
public int Id { get; set; }
public string Name { get; set; }
public string ALotOfOtherProperties { get; set; }
}
class SampleEqualityComparer : IEqualityComparer<Sample>
{
public bool Equals(Sample x, Sample y)
{
if (x.Id >= 0 && y.Id >= 0)
{
return x.Id == y.Id;
}
return x.Name.Equals(y.Name, StringComparison.CurrentCultureIgnoreCase);
}
public int GetHashCode(Sample obj)
{
//try with only name now
return obj.Name.GetHashCode();
//return 0;
}
}
This approach works perfectly fine as long as the Name property is not modified. Understandably, the Hash value no longer matches the original item in the Dictionary when the Name is modified.
Is it possible to force the Dictionary to recalculate the hash of its keys or any other workaround if it is not possible directly.?
It is really a performance hit when using a custom class as a key. The handling can take a 10 times longer.
I suggest that you have a dictionary for name and one for id.
I recommend that you set your Name and Id setter to private like:public string Name { get; private set; }
class SampleCollection
{
public SampleCollection()
{
NameLookup = new Dictionary<string, List<Sample>>();
IdLookup = new Dictionary<int, Sample>();
}
private Dictionary<string, List<Sample>> NameLookup;
private Dictionary<int, Sample> IdLookup;
public void Add(Sample sample)
{
IdLookup.Add(sample.Id, Sample);
List<Sample> list;
if (!NameLookup.TryGetValue(sample.Name, out list))
NameLookup.Add(sample.Name, list = new List<Sample>());
list.Add(Sample);
}
public Sample FindById(int id)
{
Sample result;
IdLookup.TryGetValue(id, out result);
return result;
}
public IEnumerable<Sample> FindByName(string name)
{
List<Sample> list;
if (NameLookup.TryGetValue(name, out list))
foreach(var sample in list)
yield return sample;
}
}
Can I create an object from class person inside a class employee and access to the methods and members of class person through employee class using the person’s object that I created in class employee
public class Person
{
protected string _name;
public int _age;
public string Name
{
get { return _name; }
set { _name = value; }
}
public int Age
{
get { return _age; }
set { _age = value; }
}
}
class Employee
{
Person person = new Person();
}
Do you mean this?
public class Employee
{
private Person person = new Person();
public string Name
{
get { return person.Name; }
set { person.Name = value; }
}
public int Age
{
get { return person.Age; }
set { person.Age = value; }
}
}
You could do:
class Employee
{
Person person = new Person();
public string Name
{
get { return person.Name; }
set { person.Name = value }
}
public int Age
{
get { return person.Age; }
set { person.Age = value; }
}
}
You could look at providing a 'person' interface and letting the employee class implement it.
Yes, because class Person is public.
I'll show a problem by example. There is a base class with fluent interface:
class FluentPerson
{
private string _FirstName = String.Empty;
private string _LastName = String.Empty;
public FluentPerson WithFirstName(string firstName)
{
_FirstName = firstName;
return this;
}
public FluentPerson WithLastName(string lastName)
{
_LastName = lastName;
return this;
}
public override string ToString()
{
return String.Format("First name: {0} last name: {1}", _FirstName, _LastName);
}
}
and a child class:
class FluentCustomer : FluentPerson
{
private long _Id;
private string _AccountNumber = String.Empty;
public FluentCustomer WithAccountNumber(string accountNumber)
{
_AccountNumber = accountNumber;
return this;
}
public FluentCustomer WithId(long id)
{
_Id = id;
return this;
}
public override string ToString()
{
return base.ToString() + String.Format(" account number: {0} id: {1}", _AccountNumber, _Id);
}
}
The problem is that when you call customer.WithAccountNumber("000").WithFirstName("John").WithLastName("Smith") you can't add .WithId(123) in the end because return type of the WithLastName() method is FluentPerson (not FluentCustomer).
How this problem usually solved?
Try to use some Extension methods.
static class FluentManager
{
public static T WithFirstName<T>(this T person, string firstName) where T : FluentPerson
{
person.FirstName = firstName;
return person;
}
public static T WithId<T>(this T customer, long id) where T : FluentCustomer
{
customer.ID = id;
return customer;
}
}
class FluentPerson
{
public string FirstName { private get; set; }
public string LastName { private get; set; }
public override string ToString()
{
return string.Format("First name: {0} last name: {1}", FirstName, LastName);
}
}
class FluentCustomer : FluentPerson
{
public long ID { private get; set; }
public long AccountNumber { private get; set; }
public override string ToString()
{
return base.ToString() + string.Format(" account number: {0} id: {1}", AccountNumber, ID);
}
}
after you can use like
new FluentCustomer().WithId(22).WithFirstName("dfd").WithId(32);
You can use generics to achieve that.
public class FluentPerson<T>
where T : FluentPerson<T>
{
public T WithFirstName(string firstName)
{
// ...
return (T)this;
}
public T WithLastName(string lastName)
{
// ...
return (T)this;
}
}
public class FluentCustomer : FluentPerson<FluentCustomer>
{
public FluentCustomer WithAccountNumber(string accountNumber)
{
// ...
return this;
}
}
And now:
var customer = new FluentCustomer()
.WithAccountNumber("123")
.WithFirstName("Abc")
.WithLastName("Def")
.ToString();
A solution where you need fluent interface, inheritance and also some generics...
Anyhow as I stated before: this is the only option if you want to use inheritance and access also protected members...
public class GridEx<TC, T> where TC : GridEx<TC, T>
{
public TC Build(T type)
{
return (TC) this;
}
}
public class GridExEx : GridEx<GridExEx, int>
{
}
class Program
{
static void Main(string[] args)
{
new GridExEx().Build(1);
}
}
Logically you need to configure stuff from most specific (customer) to least specific (person) or otherwise it is even hard to read it despite the fluent interface. Following this rule in most cases you won't need get into trouble. If however for any reason you still need to mix it you can use intermediate emphasizing statements like
static class Customers
{
public static Customer AsCustomer(this Person person)
{
return (Customer)person;
}
}
customer.WIthLastName("Bob").AsCustomer().WithId(10);
public class FluentPerson
{
private string _FirstName = String.Empty;
private string _LastName = String.Empty;
public FluentPerson WithFirstName(string firstName)
{
_FirstName = firstName;
return this;
}
public FluentPerson WithLastName(string lastName)
{
_LastName = lastName;
return this;
}
public override string ToString()
{
return String.Format("First name: {0} last name: {1}", _FirstName, _LastName);
}
}
public class FluentCustomer
{
private string _AccountNumber = String.Empty;
private string _id = String.Empty;
FluentPerson objPers=new FluentPerson();
public FluentCustomer WithAccountNumber(string accountNumber)
{
_AccountNumber = accountNumber;
return this;
}
public FluentCustomer WithId(string id)
{
_id = id;
return this;
}
public FluentCustomer WithFirstName(string firstName)
{
objPers.WithFirstName(firstName);
return this;
}
public FluentCustomer WithLastName(string lastName)
{
objPers.WithLastName(lastName);
return this;
}
public override string ToString()
{
return objPers.ToString() + String.Format(" account number: {0}", _AccountNumber);
}
}
And invoke it using
var ss = new FluentCustomer().WithAccountNumber("111").WithFirstName("ram").WithLastName("v").WithId("444").ToString();
Is a fluent interface really the best call here, or would an initializer be better?
var p = new Person{
LastName = "Smith",
FirstName = "John"
};
var c = new Customer{
LastName = "Smith",
FirstName = "John",
AccountNumber = "000",
ID = "123"
};
Unlike a fluent interface, this works fine without inherited methods giving back the base class and messing up the chain. When you inherit a property, the caller really shouldn't care whether FirstName was first implemented in Person or Customer or Object.
I find this more readable as well, whether on one line or multiple, and you don't have to go through the trouble of providing fluent self-decorating functions that correspond with each property.
I know this is now an old question, but I wanted to share my thoughts about this with you.
What about separating fluency, which is a kind of mechanism, and your classes, when you can ? This would leave your classes pure.
What about something like this ?
The classes
public class Person
{
public string FirstName { get; set; }
public string LastName {get; set;}
public override string ToString()
{
return $"First name: {FirstName} last name: {LastName}";
}
}
public class Customer : Person
{
public string AccountNumber { get; set; }
public long Id { get; set; }
public override string ToString()
{
return base.ToString() + $" account number: {AccountNumber} id: {Id}");
}
}
A class that adds some fluent mechanism
public class FluentCustomer
{
private Customer Customer { get; }
public FluentCustomer() : this(new Customer())
{
}
private FluentCustomer(Customer customer)
{
Customer = customer;
}
public FluentCustomer WithAccountNumber(string accountNumber)
{
Customer.AccountNumber = accountNumber;
return this;
}
public FluentCustomer WithId(long id)
{
Customer.Id = id;
return this;
}
public FluentCustomer WithFirstName(string firstName)
{
Customer.FirstName = firstName;
return this;
}
public FluentCustomer WithLastName(string lastName)
{
Customer.LastName = lastName;
return this;
}
public static implicit operator Customer(FluentCustomer fc)
{
return fc.Customer;
}
public static implicit operator FluentCustomer(Customer customer)
{
return new FluentCustomer(customer);
}
}
An extension method to switch to fluent mode
public static class CustomerExtensions
{
public static FluentCustomer Fluent(this Customer customer)
{
return customer;
}
}
The same example as in question
Customer customer = new Customer().Fluent()
.WithAccountNumber("000")
.WithFirstName("John")
.WithLastName("Smith")
.WithId(123);