C# generic method for returning maxId - c#

I would like to have a method that could perform this code on other objects I have (For example: prize, person, team and so on.), so I don't have to write the same code multiple times and just put let's say GetMaxId(List< Person > persons, Person person).
Each of my objects has an Id property.
I'm using this so when i save to text file through user input in my winform application, so i can generate the id that be 1 bigger based on the current number of eg Persons in the text file.
public static int GetMaxId(List<Prize> prizes, Prize prize)
{
int maxId = 1;
if (prizes.Count > 0)
maxId = prizes.Max(p => p.Id) + 1;
prize.Id = maxId;
return prize.Id;
}
So, what i would like is in each of the classes, for example i want to return the id for the person when creating a new person but i don't want to modify the code from taking in parameters for Prize and having to change it to Person.
i would like a method that takes generic parameters so when i call it in Person class, i can just pass the (list persons, Person person).
I don't know which type to pass in the original method so that i can reuse it in other classes.

Well, I think what you want is a generic function to retrieve the next id of a collection. You can try using generics.
Something like this:
public static int GetNextId<T>(List<T> items, Func<T,int> selector)
{
if (items.Count < 1)
return 1;
return items.Max(selector)+1;
}
And you use the function like this:
public class Person
{
public int PersonID { get; set; }
}
public static void Test()
{
var persons = new List<Person>()
{
new Person() {PersonID=1 },
new Person() {PersonID=2 },
};
var nextId = GetNextId(persons, i => i.PersonID);//returns 3
}

Here's a simple example using an interface, where all your things would implement this IHaveId interface to ensure they have this id property. The getMaxId function is generic and requires only that your list be a list of things with id properties which implement the IHaveId interface.
You can see this working at https://dotnetfiddle.net/pnX7Ph.
public interface IHaveId {
int id { get; }
}
public class Thing1 : IHaveId {
private int _id;
public Thing1(int id) {
this._id = id;
}
int IHaveId.id {
get { return this._id; }
}
}
public class Thing2 : IHaveId {
private int _id;
public Thing2(int id) {
this._id = id;
}
int IHaveId.id {
get { return this._id; }
}
}
public static int getMaxId<T>(List<T> list) where T : IHaveId {
return list.Max(i => i.id);
}
public static void Main()
{
List<IHaveId> things = new List<IHaveId>();
for (var i=0; i<5; i++) {
things.Add(new Thing1(i));
}
for (var i=10; i<15; i++) {
things.Add(new Thing2(i));
}
Console.WriteLine("Max id is " + getMaxId(things));
}

Related

How to check equivalence using Fluent Assertion Should().BeEquivalentTo() when using derived classes

I'm having problems trying to get Should().BeEquivalentTo() to work with types that derive from a base class and implement a collection interface:
public class Entity
{
public string Id {get; set;}
public string Name {get; set;}
}
public class Derived : Entity, ICollection<Entity>
{
private List<Entity> m_Children = new List<Entity>();
public string Description { get; set; }
public int Count => ((ICollection<Entity>)m_Children).Count;
public bool IsReadOnly => ((ICollection<Entity>)m_Children).IsReadOnly;
public void Add(Entity item)
{
((ICollection<Entity>)m_Children).Add(item);
}
public void Clear()
{
((ICollection<Entity>)m_Children).Clear();
}
public bool Contains(Entity item)
{
return ((ICollection<Entity>)m_Children).Contains(item);
}
public void CopyTo(Entity[] array, int arrayIndex)
{
((ICollection<Entity>)m_Children).CopyTo(array, arrayIndex);
}
public IEnumerator<Entity> GetEnumerator()
{
return ((ICollection<Entity>)m_Children).GetEnumerator();
}
public bool Remove(Entity item)
{
return ((ICollection<Entity>)m_Children).Remove(item);
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((ICollection<Entity>)m_Children).GetEnumerator();
}
}
The Test
[TestMethod]
public void EquivalenceTest()
{
var expected = new Derived
{
Id = "123",
Name = "abc",
Description = "def"
};
var actual = new Derived
{
Id = "121",
Name = "xyz",
Description = "def"
};
actual.Should().BeEquivalentTo(expected); // This succeeds, but should fail
}
The call to BeEquivalentTo seems to be ignoring the properties that are defined in the object, and only treating the object as a collection.
How can I get the framework to check the properties and the contents of the collection?
Edit
It seems like this is a known issue
Does anyone know of a workaround?
It's a known issue when comparing classes that implements IEnumerable and have extra properties to be compared.
Here's a way to hack the comparison.
public class Entity : IEnumerable<int>
{
private int[] ints = new[] { 1 };
public int Id { get; set; }
public string Name { get; set; }
public IEnumerator<int> GetEnumerator() => ((IEnumerable<int>)ints).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<int>)ints).GetEnumerator();
}
[TestMethod]
public void EquivalenceTest()
{
var expected = new Entity
{
Id = 1,
Name = "abc",
};
var actual = new Entity
{
Id = 1,
Name = "abc",
};
actual.Should().BeEquivalentTo(expected, opt => opt
.Using<Entity>(e =>
e.Subject.Should().Match<Entity>(f => f.Name == e.Expectation.Name)
.And.Subject.Should().Match<Entity>(f => f.Id == e.Expectation.Id)
.And.Subject.Should().BeEquivalentTo(e.Expectation)
)
.WhenTypeIs<Entity>());
}

C# Interface: extracting additional public property value (not part of interface) from a concrete class

Code sample to begin with:
internal class ClubHouse : ILeasable
{
public int Id { get; set; }
public int AreaInSquareFeet { get; set; }
}
public class Parking : ILeasable
{
public int Id { get; set; }
public int CarCapacity { get; set; }
}
internal interface ILeasable
{
int Id { get; set; }
}
class LeasableRepository
{
private List<ILeasable> _leasable = new List<ILeasable>()
{
new ClubHouse() {Id = 208, AreaInSquareFeet = 7500 },
new ShowRoom(){ Id = 202, AreaInSquareFeet = 4000 },
new Parking() {Id = 504, CarCapacity = 4},
};
private Dictionary<int, ILeasable> _leasableDictionary = new Dictionary<int, ILeasable>();
public LeasableRepository()
{
_leasableDictionary = _leasable.ToDictionary(x => x.Id, x => x);
}
public ILeasable GetLeasable(int id)
{
if (_leasableDictionary.ContainsKey(id)) return _leasableDictionary[id];
return null;
}
}
public class ChargeCalculatingFacade
{
LeasableRepository leasableRepository = new LeasableRepository();
public void ShowLeasingCharges(int id)
{
var leasable = leasableRepository.GetLeasable(id);
var leasingCharge = GetLeasingCharges(leasable);
}
private int GetLeasingCharges(ILeasable leasable)
{
// This is not possible as I can't be sure that leasable is ClubHouse
var property = (ClubHouse) leasable;
var areaInSquareFeet = property.AreaInSquareFeet;
return areaInSquareFeet * 10;
}
}
Now, in class ChargeCalculatingFacade class, in method ShowLeasingCharges(int id), based on the id, I called GetLeasable(int id) which returns one of the implementation of ILeasable. However it return as an interface ILeasable.
I pass that ILeasable to a private method GetLeasingCharges(leasable) to calculate the leasing charges based on the AreaInSquareFeet.
Now, leasable parameter is just ILeasable, which has just "Id" property available. Now how to identify which concreat class implementation is passed as parameter, I can cast it to get AreaInSquareFeet like this
var property = (ClubHouse) leasable;
var areaInSquareFeet = property.AreaInSquareFeet;
But the above code is not posible as I am not sure if the leasable is ClubHouse as it just picks leasable from a dictionary based on Id.
All class does not have the same additional property. For instance, Parking has additional property as "CarCapacity". I have 10 such classes, now cannot put 10 if logic to check if the interface is of required class type.
I wonder if some design pattern or some SOLID principle can simplify the design.
I have following questions:
How do I get the areaInSquareFeet in such case
Is this a good practice to have an interface with few methods and properties and again have additional public methods or properties in concreate class.
Note: I do not want to use reflection. I would like to change a design in case without reflection is not possible. Any design suggestions? Any desing pattern can be used in such scenario?'
Thank you.
Mita
A. ILeasable.GetLeasingCharges
If GetLeasingCharges depends only on the data the object already has I could be argued that it may be better choice to make GetLeasingCharges part of ILeasable.
internal interface ILeasable
{
int Id { get; set; }
int GetLeasingCharges();
}
internal class ClubHouse : ILeasable
{
public int Id { get; set; }
public int AreaInSquareFeet { get; set; }
public int GetLeasingCharges() => AreaInSquareFeet * 10;
}
internal class ClubHouse : ILeasable
{
public int Id { get; set; }
public int CarCapcity{ get; set; }
public int GetLeasingCharges() => CarCapcity * 15;
}
B. GetLeasingCharges not part ILeasable
From C#7.0 you can use pattern matching for situations like this.
public static int GetLeasingCharges(ILeasable leasable)
{
// From c#7.0
switch (leasable)
{
case ClubHouse c:
return c.AreaInSquareFeet * 10;
case ShowRoom s:
return s.AreaInSquareFeet * 12;
case Parking p:
throw new ArgumentException(
message: "Parkings cannot be leased!",
paramName: nameof(leasable));
default:
throw new ArgumentException(
message: "Unknown type",
paramName: nameof(leasable));
}
}
Before C#7.0 you could use if.
if (leasable is ClubHouse)
{
var c = (ClubHouse)leasable;
return c.AreaInSquareFeet * 10;
}
else if (leasable is ShowRoom)
{
var c = (ShowRoom)leasable;
return s.AreaInSquareFeet * 12;
}
else if(leasable is Parking)
{
throw new ArgumentException(
message: "Parkings cannot be leased!",
paramName: nameof(leasable));
}
else
{
throw new ArgumentException(
message: "Unknown type",
paramName: nameof(leasable));
}
I quite agree with #tymtam approach. You can also use an abstract class in an alternative.
public abstract class ChargeCalculatingFacadeBase<T> where T : ILeasable
{
LeasableRepository leasableRepository = new LeasableRepository();
public ILeasable leasable;
public void ShowLeasingCharges(int id)
{
leasable = leasableRepository.GetLeasable(id);
var leasingCharge = GetLeasingCharges((T)leasable);
}
public abstract int GetLeasingCharges(T leasable);
}
public class ChargeCalculatingFacade : ChargeCalculatingFacadeBase<ClubHouse>
{
public override int GetLeasingCharges(ClubHouse leasable)
{
var property = leasable;
var areaInSquareFeet = property.AreaInSquareFeet;
return areaInSquareFeet * 10;
}
}
While this might be an overkill, in a case similar to yours I have on a few occasions used a pseudo-DSL approach.
That is, I first come up with a language to express my intent, and then implement it.
What do you need? The ability to express calculations in a readable way. Let's do it this way: assuming you have a class
public class LeaseCalculator
{
public int CalculateLease(int id) ...
I'd like to initialize it like this:
var builder = new LeaseCalculatorBuilder();
LeaseCalculator calculator = builder
.On<ClubHouse>(house => house.AreaInSquareFeet)
.On<Parking>(park => park.CarCapacity)
.On<ShowRoom>(room => room.AreaInSquareFeet)
.Build(leasableRepository);
Is the intent clear? I believe so. If we have a club house, we do the first thing; for parking, something else, etc, etc.
Now, to the implementation. I could also walk step by step, but to cut story short:
public class LeaseCalculatorBuilder
{
internal Dictionary<Type, Func<ILeasable, int>> Calculations { get; } = new Dictionary<Type, Func<ILeasable, int>>();
internal LeaseCalculatorBuilder On<T>(Func<T, int> calculation) where T : class, ILeasable
{
Calculations.Add(typeof(T), (ILeasable c) => calculation((T)c));
return this;
}
internal LeaseCalculator Build(LeasableRepository leasableRepository)
{
return new LeaseCalculator(leasableRepository, this);
}
}
public class LeaseCalculator
{
private readonly Dictionary<Type, Func<ILeasable, int>> _calculations;
private readonly LeasableRepository _leasableRepository;
internal LeaseCalculator(LeasableRepository leasableRepository, LeaseCalculatorBuilder builder)
{
_leasableRepository = leasableRepository;
_calculations = builder.Calculations;
}
public int CalculateLease(int id)
{
ILeasable property = _leasableRepository.GetLeasable(id);
Type type = property.GetType();
if (_calculations.TryGetValue(type, out var calculation))
{
return calculation(property);
}
throw new Exception("Unexpected type, please extend the calculator");
}
}
And finally, a default creator:
public static class DefaultLeaseCalculator
{
internal static LeaseCalculator Build(LeasableRepository leasableRepository)
{
var builder = new LeaseCalculatorBuilder();
LeaseCalculator calculator = builder
.On<ClubHouse>(house => house.AreaInSquareFeet)
.On<Parking>(park => park.CarCapacity)
.On<ShowRoom>(room => room.AreaInSquareFeet)
.Build(leasableRepository);
return calculator;
}
}
Neat?

Create Generic Method that accepts a List with custom object types and access similar properties

I am creating a search algorithm that searches through a list with custom objects I have created. They share similar properties, but I can not seem to "implicitly" access these properties..? An example:
public class Exit{
int ID {get;set;}
}
public class Room{
int ID {get;set;}
}
static void Main(string[] args){
List<Exit> exits = new List<Exit>();
List<Room> rooms = new List<Room>();
// added numerous instances of objects to both lists
int getExitID = _GetIDFromList(exits, 2); //example
int getRoomID = _GetIDFromList(rooms, 7); //example
}
private int _GetIDFromList<T>(List<T> list, int indexOfList){
return list[indexOfList].ID; // this gives me error it can't find ID
}
Is this possible? What do I need to modify to what I have to do this??
Thank you.
You can create interface for it:
public interface IId
{
int ID { get; set; }
}
public class Exit : IId
{
int ID { get; set; }
}
public class Room : IId
{
int ID { get; set; }
}
private int _GetIDFromList<T>(List<T> list, int indexOfList) where T : IId
{
return list[indexOfList].ID;
}
Or you can use Reflection and Expression for it:
public static Expression<Func<T, P>> GetGetter<T, P>(string propName)
{
var parameter = Expression.Parameter(typeof(T));
var property = Expression.PropertyOrField(parameter, propName);
return Expression.Lambda<Func<T, P>>(property, parameter);
}
Retrives int Id from type T and returns it:
private static int _GetIDFromList<T>(List<T> list, int indexOfList)
{
var lambda = GetGetter<T, int>("Id").Compile();
return lambda(list[indexOfList]);
}
I'm little rewrote your Room class:
public class Room
{
public int ID { get; set; }
}
And usage:
Console.WriteLine(_GetIDFromList(new List<Room> { new Room { ID = 5 } }, 0));

Calling methods from inheriting classes

abstract class Person
{
public abstract void LoadName(string name);
}
class Soldier : Person
{
string soldierName;
int ID;
public override void LoadName(string name)
{
soldierName = name;
}
public void LoadName(int id)
{
ID = id;
}
}
class PersonManager
{
public void LoadNames(Person[] person, string[] names, int[] id)
{
for(int i = 0; i < p.Length; i++)
{
person[i].LoadName(names[i]);
if(person[i] is Soldier)
{
/* What I want to do:
person.LoadName(id[someValue]);
-> Cannot convert from 'string' to 'int'
or:
(Soldier)person.LoadName(id[someValue]);
-> Only assignment, call, increment, decrement and new object expressions can be used as a statement
*/
// What I have to do:
Soldier s = (Soldier)person[i];
s.LoadName(id[someValue]);
}
}
}
}
Is there a more elegant way to do this?
My original class is a lot bigger, so copying it isn't ideal.
(Note that this example is in no relation to my project, so it might not be the best example.)
You can say:
((Soldier)person[i]).LoadName(id[someValue]);
Which isn't that bad. The problem here is that person doesn't have a LoadName(int) Of course, creating an abstract overload in the parent class would fix this problem, but I'm assuming you don't want to do that. Therefore, LoadName(int) is unique to the Soldier class and this is the only way to get it.
Another way that simplifies the design and makes the code more natural is to add the overload to the Person abstract class itself. This forces any inheriting class to provide an implementation for LoadName(int id), which I think it is healthy, as id is more suited for identifying an entity.
abstract class Person
{
public abstract void LoadName(string name);
public abstract void LoadName(int id);
}
class Soldier : Person
{
string soldierName;
int ID;
public override void LoadName(string name)
{
soldierName = name;
}
public override void LoadName(int id)
{
ID = id;
}
}
class PersonManager
{
public void LoadNames(Person[] person, string[] names, int[] id)
{
for (int i = 0; i < person.Length; i++)
{
person[i].LoadName(names[i]);
person[i].LoadName(id[i]);
}
}
}
Here is one way
abstract class Person
{
public abstract void LoadName(string name);
}
class Soldier : Person
{
public string soldierName { get; set; }
public int ID { get; set; }
public override void LoadName(string name)
{
soldierName = name;
}
public void LoadName(int id)
{
ID = id;
}
}
class PersonManager
{
public void LoadNames(Person[] person, string[] names, int[] id)
{
for (int i = 0; i < p.Length; i++)
{
person[i].LoadName(names[i]);
if (person[i] is Soldier)
{
Person newPerson = new Soldier() { soldierName = names[i], ID = id[i] };
}
}
}
}
​
Or this
abstract class Person
{
public abstract void LoadName(string name, int id);
}
class Soldier : Person
{
public string soldierName { get; set; }
public int ID { get; set; }
public override void LoadName(string name, int id)
{
soldierName = name;
ID = id;
}
}
class PersonManager
{
public void LoadNames(Person[] person, string[] names, int[] id)
{
for (int i = 0; i < p.Length; i++)
{
if (person[i] is Soldier)
{
person[i].LoadName(names[i], id[i]);
}
}
}
}
​

Odd behavior when adding to an Observable Collection

I have an interesting problem. I have a Class Person:
public class Person
{
public string Name { get; set; }
public int? Score { get; set; }
public int NbrOfWins { get; set; }
public int NbrOfLosses { get; set; }
public int HighScore { get; set; }
}
I create an Observable collection:
ObservableCollection<Person> test = new ObservableCollection<Person>();
I have an extension method to add to the observable collection:
public static void myFillTest<T>(this ObservableCollection<T> value1, T value2, int nbr)
{
for (int x = 0; x < nbr; x++)
{
value1.Add(value2);
}
}
I add 5 items to the collection like this:
test.myFillTest(new Person { Name = "None" }, 5);
If I change the name in one instance:
test[2].Name = "John";
All of the items in the collection change, as if they were all pointing to the same thing.
Any reason why this would be? By the way, this works for T of type int, and string, but not for a typeof class.
This is because the class Person is a reference type while the integer is value type. When you add the same int 5 times, it is copied, when you add person 5 times, its one instance added to 5 different indexes. You can read about reference types here http://msdn.microsoft.com/en-us/library/490f96s2.aspx . You need to copy your object of type person if you want it to work as expected.
You can change your code to the following in order to always create new objects:
public static void MyFillTest<T>(this ObservableCollection<T> value1, T value2, int nbr)
{
for (int x = 0; x < nbr; x++)
{
if (typeof(T).IsValueType)
{
value1.Add(value2);
}
else
{
if (value2 is ICloneable)
{
ICloneable cloneable = (ICloneable)value2;
value1.Add((T)cloneable.Clone());
}
}
}
}
public class Person : ICloneable
{
public string Name { get; set; }
public int? Score { get; set; }
public int NbrOfWins { get; set; }
public int NbrOfLosses { get; set; }
public int HighScore { get; set; }
#region ICloneable Members
public object Clone()
{
return new Person
{
Name = this.Name,
Score = this.Score,
NbrOfWins = this.NbrOfWins,
NbrOfLosses = this.NbrOfLosses,
HighScore = this.HighScore
};
}
#endregion
}
new Person { Name = "None" } is only instantiated once, when you call your method. So they all reference to the same object.
It's quite simple - you are adding value2 to the collection nbr times. Or rather, when adding an object (as you are in your example) you are adding a reference to the same object nbr times. So if you change one, you change them all.
This extension method will do what you are trying to do:
public static void myFillTest<T>(this ObservableCollection<T> value1, Action<T> init, int nbr) where T: new()
{
for (int x = 0; x < nbr; x++)
{
var value2 = new T();
init(value2);
value1.Add(value2);
}
}
Call it like this:
test.myFillTest(p => p.Name = "None", 5);
The Person object is instantiated once and its reference is used 5 times. You could overcome this by using a memberwise clone to create shallow copies of your original object.

Categories