Sorting a `List<object>` by object properties - c#

I have some different objects that all of them have a integer field called Place. Is there a way to sort out this list without knowing what is the actual object? I mean just accessing the Place field and sort the list based on this number. possibly using linq or something?
some example objects:
public class Car
{
public int Place;
//Other related fields
}
public class Human
{
public int Place;
//Other related fields
}
//Somwhere in program
List<object> GameObjects;

You should derive your classes from a base class.
public class Base
{
public int Place;
}
public class Car : Base
{
// other properties
}
public class Human : Base
{
// other properties
}
Then you can create a list of your base type, add humans
and cars. After that you can use the Linq Sort or OrderBy method.
List<Base> list = new List<Base>();
list.Add(new Human { Place = 2 });
list.Add(new Car { Place = 1 });
var sortedList = list.Sort(x => x.Place);
More Information
The C# Station Tutorial - Lesson 8: Class Inheritance
MSDN - Queryable.OrderBy
MSDN - List.Sort Method

No because object doesn't have a Place property only Car/Human do.
There are a couple of ways you can solve this problem:
Introduce a base class
public class GameObject
{
public int Place { get; set; }
}
public class Car : GameObject
{}
public class Human : GameObject
{}
...
List<GameObject> GameObjects
Use a generic interface
public interface IGameObject
{
int Place { get; }
}
public class Car : IGameObject
{
public int Place { get; set; }
}
public class Human : IGameObject
{
public int Place { get; set; }
}
List<IGameObject> GameObjects

What you just discovered is relationship between those types. Both Car and Human seem to have a Place property, so you should extract an interface à la IGameObject.

The best way is to use an interface. If you can't, you still can do late binding using the dynamic keyword:
var list = new List<object>
{
new Car { Place = 3 },
new Human { Place = 1 },
new Car { Place = 2 }
};
var sortedList = list.OrderBy(o => ((dynamic)o).Place);

Yes, its possible using delegate methods with reflection. This is upto my knowledge, may be some other giants create it without using reflection

The best you can do is use an Interface, like this:
public Interface IFoo
{
int place;
}
And the implement that interface:
public class Car : IFoo
{
public int Place;
}
public class Human : IFoo
{
public int Place;
}
And then with linq:
List<IFoo> GameObjects;
GameObjects.OrderBy(g => g.Place);

You could let them implement an interface IPlaceable and use a property instead of only a field:
public interface IPlaceable
{
int Place { get; set; }
}
public class Car : IPlaceable
{
public int Place { get; set; }
//Other related fields
}
public class Human : IPlaceable
{
public int Place { get; set; }
//Other related fields
}
// Somwhere in program
List<IPlaceable> GameObjects;
// Somwhere else
GameObjects.OrderBy(go => go.Place);
Note that the list now is a List<IPlaceable> instead of a List<Object>.

Related

Covariance, generic, UserControl

I have created a user control that contains an ObservableCollection<Something>. I learned that I cannot cast say ObservableCollection<Tiger> to ObservableCollection<Animal>. The solution I found was to add a helper class that handles all low level collection manipulation. My suspicion is that there is a more elegant solution and if so, maybe someone can point me into that direction.
See the code below that captures the problem and my solution. Zoo corresponds to the WPF UserControl. (Actually a zoo for one type od animal.) Ideally I would define it as Zoo<T> i.e. as a generic type but that would prevent me from using XAML. I need to define Animals as object in order assign to it.
class Program
{
public static void Main(string[] args)
{
Zoo zoo = new Zoo();
List<Tiger> tigers = new List<Tiger>() { new Tiger() };
zoo.Animals = tigers;
zoo.Helper = new TigerHelper(tigers);
Console.WriteLine(zoo.GetCount());
Console.ReadLine();
}
}
public class Animal { }
public class Tiger : Animal { }
public interface Helper { int GetCount(); }
public class TigerHelper : Helper
{
private List<Tiger> tigers;
public TigerHelper(List<Tiger> tigers) { this.tigers = tigers; }
public int GetCount() { return tigers.Count; }
}
public class Zoo
{
public object Animals { get; set; }
public Helper Helper { get; set; }
public int GetCount() { return Helper.GetCount(); }
}
Rather than go all the way down to object, you can use IList. This gives you access to most of the features of the list, but without the generics. For example, you can still access the Count property:
public class Zoo
{
public IList Animals { get; set; }
public Helper Helper { get; set; }
public int GetCount() { return Animals.Count; }
}

Assign another type to specific type

I have base class thats inherited by multiple classes
public class Animal
{
public int Id { get; set; }
public static Animal Get(int id)
{
return ...
}
}
public class Cat : Animal
{
public CatPayload Payload { get; set; }
}
public class Dog : Animal
{
public DogPayload Payload { get; set; }
}
public class CatPayload
{
public int Lives { get; set; }
}
public class DogPayload
{
public bool IsDangerous { get; set; }
}
I store only Animal identifier in the database, so when I'm getting it using static method I get instance of Animal and I can't get strongly-typed instance of Payload. What would be the best way to implement this? Only thing I currently have on mind is checking type of animal instance if it matches any of the subclasses, but I'm not sure if there some simpler way?
I find your answer lacking a bit in details, so i don't know if this helps, but otherwise please extend your answer with more details, especially the parts of code that use these classes.
You can easily check with pattern matching:
// Creates a Cat, casts to an animal type
Animal myAnimal = new Cat(3);
if(myAnimal is Cat castedAnimalToCat)
{
// myCat is Animal returned true, which means we have a cat object.
// castedAnimalToCat is now a new variable of type Cat
Console.WriteLine($"{castedAnimalToCat.CatPayload}");
}
if(myAnimal is Dog castedAnimalToDog)
{
// ...
}
So somwhere in your database logic you can cast this to the right operand.
You can do some more fancier things with reflection, but your concern is always time safety and complexity with that.
1) Inheritance is supported in EF. This guide shows how it can be done:
Tutorial: Implement Inheritance with EF in an ASP.NET MVC 5 app
2) You might also consider using a flat structure for your data model in which the entities are referencing each other with foreign keys:
public class Cat
{
public int AnimalId { get; set; }
[ForeignKey(nameof(AccountId))]
public Animal Animal { get; set; }
public CatPayload Payload { get; set; }
}
3) For the payload you might use a string property for persistance containing json of the serialized class:
[NotMapped]
[JsonIgnore]
CatPayload Payload { get; set; }
public string PayloadJson
{
get => Payload == null ? null : JsonConvert.SerializeObject(Payload);
set => Payload = value == null ? null : JsonConvert.DeserializeObject<CatPayload>(value);
}

Define a generic type constraint to be of the same type as the implementation

I wonder if it is possible to force constraint on interface or abstract class generic type to be the same as the concrete class that implements it specially for it.
Lets say we want to check a fitness of certain entity to task and make it comparable to others in their proficiency
abstract class Entity
{
public abstract int Fitness(); //Bigger the number - more fit the entity is
public int MoreFitThan(Entity other)
{
return Fitness().CompareTo(other.Fitness());
}
}
class Fish : Entity
{
public int swimSpeed { get; set; }
public override int Fitness()
{
return swimSpeed;
}
}
class Human : Entity
{
public int testPoints { get; set; }
public override int Fitness()
{
return testPoints;
}
}
But now we can compare fish's speed with human's test passing capability, which doesn't make sense.
static void Main()
{
Human human = new Human() {testPoints = 10};
Fish fish = new Fish() { swimSpeed = 20 };
fish.MoreFitThan(human);
}
So is there a general way make some kind of class or interface that would force it's children classes to implement only own type to own type comparison?
Like so we could only compare people with people and fish to fish, but without explicitly specifying the type of comparable entity?
You can force the type being passed to MoreFitThan to match the inheriting class by using generics in the following way.
abstract class Entity<T> where T : Entity<T>
{
public abstract int Fitness(); //Bigger the number - more fit the entity is
public int MoreFitThan(T other)
{
return Fitness().CompareTo(other.Fitness());
}
}
class Fish : Entity<Fish>
{
public int swimSpeed { get; set; }
public override int Fitness()
{
return swimSpeed;
}
}
class Human : Entity<Human>
{
public int testPoints { get; set; }
public override int Fitness()
{
return testPoints;
}
}
Then the following would be a compilation error
Human human = new Human() {testPoints = 10};
Fish fish = new Fish() { swimSpeed = 20 };
fish.MoreFitThan(human);
because Human is not a Fish. However this would allow a class that inherits from Fish to be compared to a Fish.
class Trout : Fish
{
public int size { get; set; }
public override int Fitness()
{
return size;
}
}
The following works because a Trout is a Fish.
Trout trout = new Trout() {size = 10};
Fish fish = new Fish() { swimSpeed = 20 };
fish.MoreFitThan(trout);
My suggestion would be to create classes of comparable types, say: Swimmer, Runner, Learner that implement your interface, then in those classes also implement IComparable and enforce the constraint on that class type. Then you can extend those classes with Human for Learner, Fish for Swimmer, etc...
There are other ways to do it, but this should work fine for your needs.

How do i use generic type in my base class?

I have a class structure with a base abstract class with derived classes.
My base class looks like this:
public abstract class Graph
{
public Dictionary<Vector3, int> Dictionary { private set; get; }
public List<T> List { set; get; }
public Graph()
{
Dictionary = new Dictionary<Vector3,int>();
}
}
Then i have 2 derived classes:
public class Graph_Waypoints : Graph
{
public Graph_Waypoints() : base ()
{
List = new List<Waypoint>();
}
}
public class Graph_Tiles : Graph
{
public Graph_Tiles() : base ()
{
List = new List<Tile>();
}
}
But it seems i cannot do flexible types for my graph like this. The idea here is to create a graph that lets me use different objects for its nodes. Whether it be a way-point graph or a tile based graph.
But i am struggling to work out how to get the flexibility for it to allow me change the type when i create each new graph.
Am i going in the right direction here ? How can i get the type flexibility on my list?
You're nearly there; you're just missing some key parts:
public abstract class Graph<T> // <-- Graph must be generic
{
public Dictionary<Vector3, int> Dictionary { private set; get; }
public List<T> List { set; get; }
public Graph()
{
Dictionary = new Dictionary<Vector3, int>();
// You could initialize the list as you did before, but it's cleaner to do it here
List = new List<T>();
}
}
public class Graph_Waypoints : Graph<Waypoint> // <-- Subclasses must provide the base class generic arguments
{
public Graph_Waypoints() : base()
{
}
}
public class Graph_Tiles : Graph<Tile>
{
public Graph_Tiles() : base()
{
}
}
Also note, you do not need to explicitly write : base() when implementing argument-less constructors; the compiler does it for you

Anonymously typed List or List of Objects

I have the following problem (simplified).
I have a list of dogs:
public List<Dog> dogs { get; set; }
I currently access this list as a json object by converting it in a view:
#(new HtmlString(#Json.Encode(#ViewBag.dogs)))
I then iterate through this json object using javascript and display it on a page.
I would like to add cars to this list.
However, since the list is strongly typed as a list of dogs my first thought was to create the list as the one thing dogs and cars have in common, they're both objects.
When I tried to change my list of dogs into a list of objects, I received the following error
Cannot implicitly convert type 'System.Collections.Generic.List<object>' to System.Collections.Generic.List<dog>
I researched that and found this question which didn't help me much except to tell me that I would not be able to have a list of dogs and cars. For my purposes, however, this isn't suitable. I need my list to contain both dogs and cars, so that I have access to both of them in my application.
One solution I anticipate being suggested is that I have two separate lists, and make two separate ajax requests. However, I need to mix cars and dogs in a specific order (based on the time they were created essentially) so that solution isn't ideal.
In short, I'm wondering what the best way to accomplish this is. Perhaps I've gone off in completely the wrong direction, so I'm not opposed to doing something completely different if it makes sense.
Thanks for the help as always!
EDIT: I've tried the cast and that works. However, I need to access a property of dog (let's call it "fur") and I don't seem to be able to do that (do I need to cast again?)
'object' does not contain a definition for 'fur'
You can make list that contains both dogs and cars only if they implement the same interface or extends same class (e.g. object, then you can use typeof in condition to perform some actions on them).
EDIT:
Simple example
using System;
using System.Collections.Generic;
namespace Polymorphism
{
class Program
{
public class Car
{
public string Drive()
{
return "Wrrrr!";
}
}
public class Dog
{
public string Talk()
{
return "Woof";
}
}
static void Main()
{
var car = new Car();
var dog = new Dog();
List<object> list = new List<object>();
list.Add(car);
list.Add(dog);
foreach (object o in list)
{
if (o is Car)
Console.WriteLine((o as Car).Drive());
else
Console.WriteLine((o as Dog).Talk());
}
}
}
}
I'm sorry for that code but I copied it from Wikipedia and edited using Ideone
It's not really clear to me where the cars come in, and why you can't just change your property to be a List<object> to start with, but you can do:
List<object> objects = foo.Dogs.Cast<object>().ToList();
or in C# 4, you could use generic covariance and just write:
List<object> objects = foo.Dogs.ToList<object>();
The simplest way to have different objects in a list and access a property that they have in common is to use an Interface on the classes.
For example:
public interface ICoated {
string Coating { get; set; }
}
public class Dog : ICoated {
public string Coating {
get { return Fur; }
set { Fur = value; }
}
}
public class Car: ICoated {
public string Coating {
get { return PaintJob; }
set { PaintJob = value; }
}
}
You would then use a List<ICoated> in order to access objects that are all coated with something. Obviously, if you have many common attributes, you would then extend this model appropriately.
try to work out what's common between the two objects and use either a base class or an interface. if you used an interface, you might have it looking like this:
public interface IAnimal{
Fur Fur{ get; set; }
bool CanBark { get; set;}
}
public class Dog : IAnimal {
public Fur Fur{ get; set; }
public bool CanBark { get; set;}
}
public class Cat: IAnimal {
public Fur Fur{ get; set; }
public bool CanBark { get; set;}
}
public class Fur{
public string Color {get;set;}
public int Length {get;set}
}
etc, etc
then, your lists can be:
public List<IAnimal> dogs { get; set; }
public List<IAnimal> cats{ get; set; }
(pet) food for thought
I would probably make an interface that has shared properties, and a "Type" property.
public enum CrazyObjectType
{
Dog,
Car
}
public interface ICrazyObject
{
DateTime Date { get; }
CrazyOjbectType MyObjectType { get; }
}
public class Dog : ICrazyObject
{
public Dog()
{
MyObjectType = CrazyObjectType.Dog;
}
public DateTime Date { get; }
public CrazyObjectType MyObjectType { get; }
}
public class Car : ICrazyObject
{
public Car()
{
MyObjectType = CrazyObjectType.Car;
}
public DateTime Date { get; }
public CrazyObjectType MyObjectType { get; }
}
Then instead of List<object> you can have a List<ICrazyObject> that you check for type before casting to a car or a dog..
foreach (var myObject in myObjects)
{
if (myObject.MyObjectType == CrazyObjectType.Car)
{
var myCar = (Car)myObject;
//Do Stuff with myCar here.
}
}
This gives you the safety of knowing your type before casting it. Then whatever properties you have in type car that are different than dog. You can access easily, and safely!

Categories