Assign another type to specific type - c#

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);
}

Related

Is it possible to have extra (ignored) properties in C#?

I have a repository for a DocumentDb database. My documents all have a set of common properties so all documents implement the IDocumentEntity interface.
public interface IDocumentEntity {
[JsonProperty("id")]
Guid Id { get; set; }
[JsonProperty("documentClassification")]
DocumentClassification DocumentClassification { get; set; }
}
public class KnownDocument : IDocumentEntity {
[JsonProperty("id")]
Guid Id { get; set; }
[JsonProperty("documentClassification")]
DocumentClassification DocumentClassification { get; set; }
[JsonProperty("knownProperty")]
string KnownProperty { get; set; }
}
public class BaseDocumentRepository<T> where T : IDocumentEntity {
public Set(T entity) {
// ... stuff
}
}
This works fine with a KnownDocument where I know all of the properties. But, of course, what's great about a Document Db is that I don't need to know all of the properties (and in many cases I won't).
So my client submits something like this-
{unknownProperty1: 1, unknownProperty2: 2}
And I want to upsert this using my document repository.
public OtherDocumentService() {
_otherDocumentService = new OtherDocumentRepository();
}
public UpsertDocument(dynamic entity) {
entity.id = new Guid();
entity.documentClassification = DocumentClassification.Other;
_otherDocumentRepository.Set(entity);
}
But I get an InvalidCastException from dynamic to IDocumentEntity. I assume it's because of the extra properties that exist on the dynamic object but not on the IDocumentEntity interface?
What I'm trying to do is leave my document entities open to be dynamic, but rely on a few properties being there to maintain them.
Entity parameter passed to the UpsertDocument should explicitly implement IDocumentEntity in order do make the code works, it is not enough just have a Id property.
Some options:
1) Proxy may be applied:
public class ProxyDocumentEntity : IDocumentEntity
{
public dynamic Content { get; private set; }
public ProxyDocumentEntity(dynamic #content)
{
Content = #content;
}
public Guid Id
{
get { return Content.Id; }
set { Content.Id = value; }
}
}
... using
public void UpsertDocument(dynamic entity)
{
entity.Id = new Guid();
repo.Set(new ProxyDocumentEntity(entity));
}
The stored document will have nested Object property, which may be not acceptable
2)There is a lib https://github.com/ekonbenefits/impromptu-interface which creates a proxy dynamically
and does not make extra property like solution above.
Drawback will be in performance.
Technically it could be 2 methods:
public void UpsertDocument(IDocumentEntity entity){...}
public void UpsertDocument(dynamic entity){...}
so the first (fast) will work for the objects which implement IDocumentEntity and second(slow) for the rest of the objects.
But this is a speculation a bit , as I dunno the details of the whole code base of the project you have.
If you have some flexibility as to how to name those dynamic properties, you could stuff them into a Dictionary property on your object:
public Dictionary<string, dynamic> extra { get; set; }

How to inherit from class that could be inherited by other classes and keep other classes properties (for view model)

I'm stuck in my inheritances bloating here:
First let me explain the premise of my problem.
My Model:
public class Person
{
[Key]
public int PersonId { get; set; }
[MaxLength(100)]
public string Name { get; set; }
}
public class SuperHero:Person
{
[MaxLength(100)]
public string SuperHeroName { get; set; }
public virtual ICollection<SuperPower> SuperPowers{ get; set; }
}
Now, I am trying to create my viewModels for my MVC website, I have those base classes that need to be inherited by all other viewmodel displaying/editing a Person/SuperHero:
public class BasePersonViewModel
{
public string Name { get; set; }
ctors()
}
public class BaseSuperHeroViewModel : BasePersonViewModel
{
public List<string> SuperPowers{ get; set; }
ctors()
}
Here is where I am stuck, I am trying to define only one ViewModel that could be used regarless of the base class and access property of Person and/or SuperHero (if the Person is a superhero). I've been pulling my hair out but so far only found a solution which i don't like:
Example:
public class SomeViewModel<T> where T : BasePersonViewModel
{
public BasePersonViewModel obj;
public DateTime BirthDate { get; set; }
public SomeViewModel(Person data) //: base(data)
{
if (data is SuperHero)
obj = new BaseSuperHeroViewModel (data);
else
obj = new BasePersonViewModel(data);
}
}
While this would work it's really not sexy to use. And on top of that, I could have another ViewModel that inherit from SomeViewModel as well.
Is there a cleaner way to achieve this?
Edit
My main goal is to be able to able to cast my SomeViewModel depending on the one of the baseclass. Let's say do something like in my Controller:
if myclass is SomeViewModel (of type SuperHero)
Exactly how you do it for Person/SuperHero db retrival/check
var data = context.Person.first(w=> w.Id==1)
if (data is SuperHero)
..
I would like this because I would like to use the same viewmodel let's say to list superhero and person, and just display slightly differently if it's a superhero
Edit 2
I was trying to avoid using the whole Model.Obj to be able to see it directly with the Model... But the more i think about it, the more I think this is not possible really... On top of that I would like to extend some other superHero specific properties in SomeViewModel (only if SomeViewModel is a superhero), that are not declared in the BaseSuperHeroModel one... Let's say in SomeViewModel I want the field 'ComesFromPlanet' only if superhero.
Edit 3
I thought about another way to do it, but it obviously creating various ViewModel.
For the most general case (all fields that are shared for all Person) I would keep my base:
public class BasePersonViewModel
{
public string Name { get; set; }
ctors()
}
I interface specific Person:
public Interface IBaseSuperHero
{
[MaxLength(100)]
public string SuperHeroName { get; set; }
public List<string> SuperPowers{ get; set; }
}
I would keep as well OtherViewModel like this:
public class SomeViewModel:BasePersonViewModel
{
Public datetime Birthdate {get;set;}
}
Then I would create a specific SomeviewModel for other Person inheritant and used interfaces to have old and new properties.
For example:
public class SomeViewModelSuperHero:SomeViewModel, IBaseSuperHero
{
public string OriginalPlanet {get;set;}
}
Is this a clean solution?
Sorry I'm sure I am not clear about this, but I try !
Thanks for your input and time.
I am trying to define only one ViewModel that could be used regarless of the base class and access property of Person and/or SuperHero (if the Person is a superhero)
Assuming you'd return default values for super-hero properties when the model is not a super-hero, you could do something like this:
public class PersonOrSuperHeroViewModel {
private Person person;
private SuperHero superHero;
public PersonOrSuperHeroViewModel(Person personOrSuperHero) {
if (personOrSuperHero is SuperHero) superHero = personOrSuperHero;
person = personOrSuperHero;
}
public IsSuperHero { get { return superHero != null; } }
... // super-hero properties only work when IsSuperHero == true
}
How about something like
public class Person {
public virtual BasePersonViewModel MainViewModel {
get { return new BasePersonViewModel(this);}
}
}
public class SuperHero : Person {
public override BasePersonViewModel MainViewModel {
get { return new BaseSuperHeroViewModel(this);}
}
}
So if all your people classes override the MainViewModel property to return the appropriate view, you don't need
public BasePersonViewModel obj;
public SomeViewModel(Person data) {
if (data is SuperHero)
obj = new BaseSuperHeroViewModel (data);
else
obj = new BasePersonViewModel(data);
}
Because you can have
public BasePersonViewModel obj;
public SomeViewModel(Person data) { obj = data.MainViewModel; }
which will work however many subclasses of person you have.

Sorting a `List<object>` by object properties

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>.

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!

Design problem: Get child object type information avoiding if statements in presentation layer

I have a customer hierarchy like so:
abstract class Customer {
public virtual string Name { get; set; }
}
class HighValueCustomer : Customer {
public virtual int MaxSpending { get; set; }
}
class SpecialCustomer : Customer {
public virtual string Award { get; set; }
}
When I retrieve a Customer, I would like to show on the web form the properties to edit/modify. Currently, I use if statements to find the child customer type and show the specialized properties. Is there a design pattern (visitor?) or better way so I can avoid the "if" statements in presentation layer? How do you do it?
Further information: This is an asp.net website with nHibernate backend. Each customer type has its own user control on the page that I would like to load automatically given the customer type.
Can you use reflection to get the list of properties specific to an subclass (instance)? (Less error-prone.)
If not, create a (virtual) method which returns the special properties. (More error prone!)
For an example of the latter:
abstract class Customer {
public virtual string Name { get; set; }
public virtual IDictionary<string, object> GetProperties()
{
var ret = new Dictionary<string, object>();
ret["Name"] = Name;
return ret;
}
}
class HighValueCustomer : Customer {
public virtual int MaxSpending { get; set; }
public override IDictionary<string, object> GetProperties()
{
var ret = base.GetProperties();
ret["Max spending"] = MaxSpending;
return ret;
}
}
class SpecialCustomer : Customer {
public virtual string Award { get; set; }
public override IDictionary<string, object> GetProperties()
{
var ret = base.GetProperties();
ret["Award"] = Award;
return ret;
}
}
You probably want to create sections (fieldsets?) on your Web page, anyway, so if would come into play there, making this extra coding kinda annoying and useless.
I think a cleaner organization would be to have a parallel hierarchy of display controls or formats. Maybe use something like the Abstract Factory Pattern to create both the instance of Customer and of CustomerForm at the same time. Display the returned CustomerForm instance, which would know about the extra properties and how to display and edit them.
new:
interface CustomerEdit
{
void Display();
}
edit:
abstract class Customer {
protected CustomerEdit customerEdit; // customers have an object which allows for edit
public virtual string Name { get; set; }
public void Display() { customerEdit.Display(); } // allow the CustomerEdit implementor to display the UI elements
}
// Set customerEdit in constructor, tie with "this"
class HighValueCustomer : Customer {
public virtual int MaxSpending { get; set; }
}
// Set customerEdit in constructor, tie with "this"
class SpecialCustomer : Customer {
public virtual string Award { get; set; }
}
usage:
Customer whichCouldItBe = GetSomeCustomer();
whichCouldItBe.Display(); // shows UI depeneding on the concrete type
Have you tried something like this:
public class Customer<T>
where T : Customer<T>
{
private T subClass;
public IDictionary<string, object> GetProperties()
{
return subClass.GetProperties();
}
}
With a subclass of:
public class FinancialCustomer : Customer<FinancialCustomer>
{
}
This is off the top of my head so might not work. I've seen this type of code in CSLA.NET.
Here's the link to the CSLA.NET class called BusinessBase.cs which has a similar definition to what I've given above.

Categories