Creating custom objects with custom properties using genericsSerialize C# objects of unknown type to bytes...

Password maker in c#

Why did the Japanese attack the Aleutians at the same time as Midway?

Where is the USB2 OTG port on the RPi 4 Model B located?

Is Arc Length always irrational between two rational points?

Is it rude to tell recruiters I would only change jobs for a better salary?

Correct use of ergeben?

If a specific mass of air is polluted, will the pollution stick with it?

Are there any intersection of Theory A and Theory B?

What is this welding tool I found in my attic?

What's the point of this scene involving Flash Thompson at the airport?

What is the difference between logical consistency and logical entailment in deductive logic?

Keep milk (or milk alternative) for a day without a fridge

When did the Roman Empire fall according to contemporaries?

Why would guns not work in the dungeon?

Is Trump personally blocking people on Twitter?

What's the minimum number of sensors for a hobby GPS waypoint-following UAV?

I quit, and boss offered me 3 month "grace period" where I could still come back

Why does Hellboy file down his horns?

diff shows a file that does not exist

Cubic programming and beyond?

Machine learning and operations research projects

Shortest distance around a pyramid

I have a ruthless DM and I'm considering leaving the party. What are my options to minimize the negative impact to the rest of the group?

Stuck Apple Mail - how to reset?



Creating custom objects with custom properties using generics


Serialize C# objects of unknown type to bytes using genericsSingleton implementation using genericsPolymorphic animals speak their name and make a noiseAbstract factory using genericsPrint Professor and Student Object using Inheritance in C++Rectangle ClassCreating clearly defined methods with generics and delegatesSave to a MySQL database a temporary row with all information about a receiptCSV Data Table ExtensionUsing Generics in C#






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}







3












$begingroup$


I have two base classes: City and Building:



public class City
{
public string Name { get; set; }
public double Area { get; set; }
}

public class Building
{
public string Name { get; set; }
public double Area { get; set; }
public int Stories { get; set; }
}


With two classes that inherit from Building, with their own Id property:



public class MyBuilding : Building
{
public int MyId { get; set; }
}

public class HisBuilding : Building
{
public int HisId { get; set; }
}


And two classes that inherit from City, with their own Id and IEnumerable<Building> properties:



public class MyCity : City
{
public int MyId { get; set; }
public IEnumerable<MyBuilding> Buildings { get; set; }
}

public class HisCity : City
{
public int HisId { get; set; }
public IEnumerable<HisBuilding> Buildings { get; set; }
}


Below is a method I've created that returns a KeyValuePair<City, Building> using generics:



public static KeyValuePair<TCity, IEnumerable<TBuilding>> GetData<TCity, TBuilding>()
where TCity : City, new()
where TBuilding : Building, new()
{
TCity city = new TCity();
IEnumerable<TBuilding> buildings = new List<TBuilding>();
return new KeyValuePair<TCity, IEnumerable<TBuilding>>(city, buildings);
}


And in my Main method I've logic that instantiates a specific City object based on a user's input.



int input = -1;
string strInput = Console.ReadLine();
int.TryParse(strInput, out input);
string json = string.Empty;
switch (input)
{
case 1:
KeyValuePair<MyCity, IEnumerable<MyBuilding>> myCity
= GetData<MyCity, MyBuilding>();
MyCity my = myCity.Key;
my.MyId = 1;
my.Buildings = myCity.Value;
json = JsonConvert.SerializeObject(my, Formatting.Indented);
break;

default:
KeyValuePair<HisCity, IEnumerable<HisBuilding>> hisCity
= GetData<HisCity, HisBuilding>();
HisCity his = hisCity.Key;
his.HisId = 2;
his.Buildings = hisCity.Value;
json = JsonConvert.SerializeObject(his, Formatting.Indented);
break;
}
Console.WriteLine(json);
Console.ReadLine();


The above generic method is just something I cobbled together in the last half hour, but I'm wondering if there is a more efficient way of creating these custom objects of mine, especially when each City has its own, different IEnumerable<Building> property.



EDIT



Here is the code I have for building the IEnumerable inside my GetData method:



public static IEnumerable<TBuilding> GetBuildingData<TBuilding>() 
where TBuilding : Building, new()
{
DataTable table;
string myConnectionString = @"Data Source=(LocalDb)MSSQLLocalDb;Initial Catalog=Test;Integrated Security=True;";
List<TBuilding> buildings = new List<TBuilding>();
using (SqlConnection connection = new SqlConnection(myConnectionString))
{
using (SqlCommand command = new SqlCommand("[dbo].[GetListData]", connection) { CommandType = CommandType.StoredProcedure })
{
connection.Open();
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
table = new DataTable();
adapter.Fill(table);
}
connection.Close();
}
}
foreach (DataRow row in table.Rows)
{
TBuilding building = new TBuilding();
building.Area = Convert.ToDouble(row["Area"]);
building.Name = row["Name"].ToString();
building.Stories = Convert.ToInt32(row["Stories"]);
buildings.Add(building);
}
return buildings;
}









share|improve this question











$endgroup$












  • $begingroup$
    Could you provide a working example of how you would use such functionality? Atm you just have 2 objects with empty lists. What is the point of this?
    $endgroup$
    – dfhwze
    8 hours ago










  • $begingroup$
    Best practices you should make a constructor for types that have properties of ienumerable or collection types and fill them in with a default value and not return null. For IEnumerable just use Enumerable.Empty docs.microsoft.com/en-us/dotnet/api/…
    $endgroup$
    – CharlesNRice
    7 hours ago










  • $begingroup$
    @dfhwze I work with multiple clients and send them all notifications periodically. The notifications contain some of the same data, but Id properties are client-specific, so I'm working to build out the base objects generically, then add the custom ids later on.
    $endgroup$
    – Delfino
    7 hours ago










  • $begingroup$
    Your method creates an empty list. How would you fill this list? I find this part crucial to review your code :)
    $endgroup$
    – dfhwze
    7 hours ago








  • 1




    $begingroup$
    @dfhwze I edited my question to include the code I'm using to build that list.
    $endgroup$
    – Delfino
    7 hours ago


















3












$begingroup$


I have two base classes: City and Building:



public class City
{
public string Name { get; set; }
public double Area { get; set; }
}

public class Building
{
public string Name { get; set; }
public double Area { get; set; }
public int Stories { get; set; }
}


With two classes that inherit from Building, with their own Id property:



public class MyBuilding : Building
{
public int MyId { get; set; }
}

public class HisBuilding : Building
{
public int HisId { get; set; }
}


And two classes that inherit from City, with their own Id and IEnumerable<Building> properties:



public class MyCity : City
{
public int MyId { get; set; }
public IEnumerable<MyBuilding> Buildings { get; set; }
}

public class HisCity : City
{
public int HisId { get; set; }
public IEnumerable<HisBuilding> Buildings { get; set; }
}


Below is a method I've created that returns a KeyValuePair<City, Building> using generics:



public static KeyValuePair<TCity, IEnumerable<TBuilding>> GetData<TCity, TBuilding>()
where TCity : City, new()
where TBuilding : Building, new()
{
TCity city = new TCity();
IEnumerable<TBuilding> buildings = new List<TBuilding>();
return new KeyValuePair<TCity, IEnumerable<TBuilding>>(city, buildings);
}


And in my Main method I've logic that instantiates a specific City object based on a user's input.



int input = -1;
string strInput = Console.ReadLine();
int.TryParse(strInput, out input);
string json = string.Empty;
switch (input)
{
case 1:
KeyValuePair<MyCity, IEnumerable<MyBuilding>> myCity
= GetData<MyCity, MyBuilding>();
MyCity my = myCity.Key;
my.MyId = 1;
my.Buildings = myCity.Value;
json = JsonConvert.SerializeObject(my, Formatting.Indented);
break;

default:
KeyValuePair<HisCity, IEnumerable<HisBuilding>> hisCity
= GetData<HisCity, HisBuilding>();
HisCity his = hisCity.Key;
his.HisId = 2;
his.Buildings = hisCity.Value;
json = JsonConvert.SerializeObject(his, Formatting.Indented);
break;
}
Console.WriteLine(json);
Console.ReadLine();


The above generic method is just something I cobbled together in the last half hour, but I'm wondering if there is a more efficient way of creating these custom objects of mine, especially when each City has its own, different IEnumerable<Building> property.



EDIT



Here is the code I have for building the IEnumerable inside my GetData method:



public static IEnumerable<TBuilding> GetBuildingData<TBuilding>() 
where TBuilding : Building, new()
{
DataTable table;
string myConnectionString = @"Data Source=(LocalDb)MSSQLLocalDb;Initial Catalog=Test;Integrated Security=True;";
List<TBuilding> buildings = new List<TBuilding>();
using (SqlConnection connection = new SqlConnection(myConnectionString))
{
using (SqlCommand command = new SqlCommand("[dbo].[GetListData]", connection) { CommandType = CommandType.StoredProcedure })
{
connection.Open();
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
table = new DataTable();
adapter.Fill(table);
}
connection.Close();
}
}
foreach (DataRow row in table.Rows)
{
TBuilding building = new TBuilding();
building.Area = Convert.ToDouble(row["Area"]);
building.Name = row["Name"].ToString();
building.Stories = Convert.ToInt32(row["Stories"]);
buildings.Add(building);
}
return buildings;
}









share|improve this question











$endgroup$












  • $begingroup$
    Could you provide a working example of how you would use such functionality? Atm you just have 2 objects with empty lists. What is the point of this?
    $endgroup$
    – dfhwze
    8 hours ago










  • $begingroup$
    Best practices you should make a constructor for types that have properties of ienumerable or collection types and fill them in with a default value and not return null. For IEnumerable just use Enumerable.Empty docs.microsoft.com/en-us/dotnet/api/…
    $endgroup$
    – CharlesNRice
    7 hours ago










  • $begingroup$
    @dfhwze I work with multiple clients and send them all notifications periodically. The notifications contain some of the same data, but Id properties are client-specific, so I'm working to build out the base objects generically, then add the custom ids later on.
    $endgroup$
    – Delfino
    7 hours ago










  • $begingroup$
    Your method creates an empty list. How would you fill this list? I find this part crucial to review your code :)
    $endgroup$
    – dfhwze
    7 hours ago








  • 1




    $begingroup$
    @dfhwze I edited my question to include the code I'm using to build that list.
    $endgroup$
    – Delfino
    7 hours ago














3












3








3





$begingroup$


I have two base classes: City and Building:



public class City
{
public string Name { get; set; }
public double Area { get; set; }
}

public class Building
{
public string Name { get; set; }
public double Area { get; set; }
public int Stories { get; set; }
}


With two classes that inherit from Building, with their own Id property:



public class MyBuilding : Building
{
public int MyId { get; set; }
}

public class HisBuilding : Building
{
public int HisId { get; set; }
}


And two classes that inherit from City, with their own Id and IEnumerable<Building> properties:



public class MyCity : City
{
public int MyId { get; set; }
public IEnumerable<MyBuilding> Buildings { get; set; }
}

public class HisCity : City
{
public int HisId { get; set; }
public IEnumerable<HisBuilding> Buildings { get; set; }
}


Below is a method I've created that returns a KeyValuePair<City, Building> using generics:



public static KeyValuePair<TCity, IEnumerable<TBuilding>> GetData<TCity, TBuilding>()
where TCity : City, new()
where TBuilding : Building, new()
{
TCity city = new TCity();
IEnumerable<TBuilding> buildings = new List<TBuilding>();
return new KeyValuePair<TCity, IEnumerable<TBuilding>>(city, buildings);
}


And in my Main method I've logic that instantiates a specific City object based on a user's input.



int input = -1;
string strInput = Console.ReadLine();
int.TryParse(strInput, out input);
string json = string.Empty;
switch (input)
{
case 1:
KeyValuePair<MyCity, IEnumerable<MyBuilding>> myCity
= GetData<MyCity, MyBuilding>();
MyCity my = myCity.Key;
my.MyId = 1;
my.Buildings = myCity.Value;
json = JsonConvert.SerializeObject(my, Formatting.Indented);
break;

default:
KeyValuePair<HisCity, IEnumerable<HisBuilding>> hisCity
= GetData<HisCity, HisBuilding>();
HisCity his = hisCity.Key;
his.HisId = 2;
his.Buildings = hisCity.Value;
json = JsonConvert.SerializeObject(his, Formatting.Indented);
break;
}
Console.WriteLine(json);
Console.ReadLine();


The above generic method is just something I cobbled together in the last half hour, but I'm wondering if there is a more efficient way of creating these custom objects of mine, especially when each City has its own, different IEnumerable<Building> property.



EDIT



Here is the code I have for building the IEnumerable inside my GetData method:



public static IEnumerable<TBuilding> GetBuildingData<TBuilding>() 
where TBuilding : Building, new()
{
DataTable table;
string myConnectionString = @"Data Source=(LocalDb)MSSQLLocalDb;Initial Catalog=Test;Integrated Security=True;";
List<TBuilding> buildings = new List<TBuilding>();
using (SqlConnection connection = new SqlConnection(myConnectionString))
{
using (SqlCommand command = new SqlCommand("[dbo].[GetListData]", connection) { CommandType = CommandType.StoredProcedure })
{
connection.Open();
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
table = new DataTable();
adapter.Fill(table);
}
connection.Close();
}
}
foreach (DataRow row in table.Rows)
{
TBuilding building = new TBuilding();
building.Area = Convert.ToDouble(row["Area"]);
building.Name = row["Name"].ToString();
building.Stories = Convert.ToInt32(row["Stories"]);
buildings.Add(building);
}
return buildings;
}









share|improve this question











$endgroup$




I have two base classes: City and Building:



public class City
{
public string Name { get; set; }
public double Area { get; set; }
}

public class Building
{
public string Name { get; set; }
public double Area { get; set; }
public int Stories { get; set; }
}


With two classes that inherit from Building, with their own Id property:



public class MyBuilding : Building
{
public int MyId { get; set; }
}

public class HisBuilding : Building
{
public int HisId { get; set; }
}


And two classes that inherit from City, with their own Id and IEnumerable<Building> properties:



public class MyCity : City
{
public int MyId { get; set; }
public IEnumerable<MyBuilding> Buildings { get; set; }
}

public class HisCity : City
{
public int HisId { get; set; }
public IEnumerable<HisBuilding> Buildings { get; set; }
}


Below is a method I've created that returns a KeyValuePair<City, Building> using generics:



public static KeyValuePair<TCity, IEnumerable<TBuilding>> GetData<TCity, TBuilding>()
where TCity : City, new()
where TBuilding : Building, new()
{
TCity city = new TCity();
IEnumerable<TBuilding> buildings = new List<TBuilding>();
return new KeyValuePair<TCity, IEnumerable<TBuilding>>(city, buildings);
}


And in my Main method I've logic that instantiates a specific City object based on a user's input.



int input = -1;
string strInput = Console.ReadLine();
int.TryParse(strInput, out input);
string json = string.Empty;
switch (input)
{
case 1:
KeyValuePair<MyCity, IEnumerable<MyBuilding>> myCity
= GetData<MyCity, MyBuilding>();
MyCity my = myCity.Key;
my.MyId = 1;
my.Buildings = myCity.Value;
json = JsonConvert.SerializeObject(my, Formatting.Indented);
break;

default:
KeyValuePair<HisCity, IEnumerable<HisBuilding>> hisCity
= GetData<HisCity, HisBuilding>();
HisCity his = hisCity.Key;
his.HisId = 2;
his.Buildings = hisCity.Value;
json = JsonConvert.SerializeObject(his, Formatting.Indented);
break;
}
Console.WriteLine(json);
Console.ReadLine();


The above generic method is just something I cobbled together in the last half hour, but I'm wondering if there is a more efficient way of creating these custom objects of mine, especially when each City has its own, different IEnumerable<Building> property.



EDIT



Here is the code I have for building the IEnumerable inside my GetData method:



public static IEnumerable<TBuilding> GetBuildingData<TBuilding>() 
where TBuilding : Building, new()
{
DataTable table;
string myConnectionString = @"Data Source=(LocalDb)MSSQLLocalDb;Initial Catalog=Test;Integrated Security=True;";
List<TBuilding> buildings = new List<TBuilding>();
using (SqlConnection connection = new SqlConnection(myConnectionString))
{
using (SqlCommand command = new SqlCommand("[dbo].[GetListData]", connection) { CommandType = CommandType.StoredProcedure })
{
connection.Open();
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
table = new DataTable();
adapter.Fill(table);
}
connection.Close();
}
}
foreach (DataRow row in table.Rows)
{
TBuilding building = new TBuilding();
building.Area = Convert.ToDouble(row["Area"]);
building.Name = row["Name"].ToString();
building.Stories = Convert.ToInt32(row["Stories"]);
buildings.Add(building);
}
return buildings;
}






c# generics inheritance






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 7 hours ago







Delfino

















asked 8 hours ago









DelfinoDelfino

2411 silver badge7 bronze badges




2411 silver badge7 bronze badges












  • $begingroup$
    Could you provide a working example of how you would use such functionality? Atm you just have 2 objects with empty lists. What is the point of this?
    $endgroup$
    – dfhwze
    8 hours ago










  • $begingroup$
    Best practices you should make a constructor for types that have properties of ienumerable or collection types and fill them in with a default value and not return null. For IEnumerable just use Enumerable.Empty docs.microsoft.com/en-us/dotnet/api/…
    $endgroup$
    – CharlesNRice
    7 hours ago










  • $begingroup$
    @dfhwze I work with multiple clients and send them all notifications periodically. The notifications contain some of the same data, but Id properties are client-specific, so I'm working to build out the base objects generically, then add the custom ids later on.
    $endgroup$
    – Delfino
    7 hours ago










  • $begingroup$
    Your method creates an empty list. How would you fill this list? I find this part crucial to review your code :)
    $endgroup$
    – dfhwze
    7 hours ago








  • 1




    $begingroup$
    @dfhwze I edited my question to include the code I'm using to build that list.
    $endgroup$
    – Delfino
    7 hours ago


















  • $begingroup$
    Could you provide a working example of how you would use such functionality? Atm you just have 2 objects with empty lists. What is the point of this?
    $endgroup$
    – dfhwze
    8 hours ago










  • $begingroup$
    Best practices you should make a constructor for types that have properties of ienumerable or collection types and fill them in with a default value and not return null. For IEnumerable just use Enumerable.Empty docs.microsoft.com/en-us/dotnet/api/…
    $endgroup$
    – CharlesNRice
    7 hours ago










  • $begingroup$
    @dfhwze I work with multiple clients and send them all notifications periodically. The notifications contain some of the same data, but Id properties are client-specific, so I'm working to build out the base objects generically, then add the custom ids later on.
    $endgroup$
    – Delfino
    7 hours ago










  • $begingroup$
    Your method creates an empty list. How would you fill this list? I find this part crucial to review your code :)
    $endgroup$
    – dfhwze
    7 hours ago








  • 1




    $begingroup$
    @dfhwze I edited my question to include the code I'm using to build that list.
    $endgroup$
    – Delfino
    7 hours ago
















$begingroup$
Could you provide a working example of how you would use such functionality? Atm you just have 2 objects with empty lists. What is the point of this?
$endgroup$
– dfhwze
8 hours ago




$begingroup$
Could you provide a working example of how you would use such functionality? Atm you just have 2 objects with empty lists. What is the point of this?
$endgroup$
– dfhwze
8 hours ago












$begingroup$
Best practices you should make a constructor for types that have properties of ienumerable or collection types and fill them in with a default value and not return null. For IEnumerable just use Enumerable.Empty docs.microsoft.com/en-us/dotnet/api/…
$endgroup$
– CharlesNRice
7 hours ago




$begingroup$
Best practices you should make a constructor for types that have properties of ienumerable or collection types and fill them in with a default value and not return null. For IEnumerable just use Enumerable.Empty docs.microsoft.com/en-us/dotnet/api/…
$endgroup$
– CharlesNRice
7 hours ago












$begingroup$
@dfhwze I work with multiple clients and send them all notifications periodically. The notifications contain some of the same data, but Id properties are client-specific, so I'm working to build out the base objects generically, then add the custom ids later on.
$endgroup$
– Delfino
7 hours ago




$begingroup$
@dfhwze I work with multiple clients and send them all notifications periodically. The notifications contain some of the same data, but Id properties are client-specific, so I'm working to build out the base objects generically, then add the custom ids later on.
$endgroup$
– Delfino
7 hours ago












$begingroup$
Your method creates an empty list. How would you fill this list? I find this part crucial to review your code :)
$endgroup$
– dfhwze
7 hours ago






$begingroup$
Your method creates an empty list. How would you fill this list? I find this part crucial to review your code :)
$endgroup$
– dfhwze
7 hours ago






1




1




$begingroup$
@dfhwze I edited my question to include the code I'm using to build that list.
$endgroup$
– Delfino
7 hours ago




$begingroup$
@dfhwze I edited my question to include the code I'm using to build that list.
$endgroup$
– Delfino
7 hours ago










2 Answers
2






active

oldest

votes


















3












$begingroup$

I will focus on..




Creating custom objects with custom properties using generics




Which you do in this method..




public static KeyValuePair<TCity, IEnumerable<TBuilding>> GetData<TCity, TBuilding>()
where TCity : City, new()
where TBuilding : Building, new()
{
TCity city = new TCity();
IEnumerable<TBuilding> buildings = new List<TBuilding>();
return new KeyValuePair<TCity, IEnumerable<TBuilding>>(city, buildings);
}




  • A KeyValuePair is archaic, you can use a ValueTuple nowadays


  • TBuilding does not require the new() constraint in this method

  • The choice for IEnumerable over IList is questionable, since you retrieve the items later on and have no way of adding them to an IEnumerable. So why create the IEnumerable in this method?

  • The name should reflect what you are doing. CreateCity seems more appropriate.


I would refactor this method..



public static (TCity city, IList<TBuilding> buildings) CreateCity<TCity, TBuilding>()
where TCity : City, new()
where TBuilding : Building
{
var city = new TCity();
var buildings = new List<TBuilding>();
return (city, buildings);
}


EDIT:



Thinking about the refactored method. This doesn't even need to be a method anymore. It doesn't do anything but create objects for the types you specify.



What I would really do is throw out this ancient way of ORM, and use an existing API (EF, NHibernate, Dapper).






share|improve this answer











$endgroup$









  • 1




    $begingroup$
    I'm afraid we might here at some point this code is simplified, in my real code I actually do this and that :-
    $endgroup$
    – t3chb0t
    6 hours ago










  • $begingroup$
    When I refactor my method using the code you've posted, by replacing the KeyValuePair<TCity, IEnumerable<TBuilding>> with (TCity city, IList<TBuilding> buildings I just end up with a bunch of errors. Could this be because I'm using Visual Studio 2015?
    $endgroup$
    – Delfino
    6 hours ago






  • 1




    $begingroup$
    ValueTuple is supported since blogs.msdn.microsoft.com/mazhou/2017/05/26/…. You could keep using KeyValuePair instead, or use a regular Tuple.
    $endgroup$
    – dfhwze
    6 hours ago






  • 1




    $begingroup$
    ...about the ancient tools... it looks like you should add another one to this list and suggest using VS2019 :-P
    $endgroup$
    – t3chb0t
    5 hours ago





















2












$begingroup$


public class MyBuilding : Building
{
public int MyId { get; set; }
}

public class HisBuilding : Building
{
public int HisId { get; set; }
}



Why do you have the id as properties of the subclasses, it's a candidate for a base class member:



public class Building
{
public int Id { get; set; }


If the subclasses must have specialized names for their Id property, then provide that as:



public class MyBuilding : Building
{
public int MyId { get { return Id; } set { Id = value; } }
}


but that is a rather odd concept that you should avoid if possible.



The same holds for Cities.





public class MyCity : City
{
public int MyId { get; set; }
public IEnumerable<MyBuilding> Buildings { get; set; }
}


Normally you would have a materialized data set for buildings instead of an IEnumerable<T> - unless you're creating the instances lazily/dynamically. You could maybe consider using a IReadonlyList<T> as type, if you don't want it to be modifiable or else just a IList<T>






public static KeyValuePair<TCity, IEnumerable<TBuilding>> GetData<TCity, TBuilding>()
where TCity : City, new()
where TBuilding : Building, new()
{
TCity city = new TCity();
IEnumerable<TBuilding> buildings = new List<TBuilding>();
return new KeyValuePair<TCity, IEnumerable<TBuilding>>(city, buildings);
}



If you changed the City base class to a generic like:



public class City<TBuilding> where TBuilding: Building
{
public IList<TBuilding> Buildings { get; set; }
}


and dropped the buildings on the specialized cities, then you could return just the city from GetData, because you can initialize the Buildings property inside GetData, which I would rename to CreateCity()



public static TCity CreateCity<TCity, TBuilding>()
where TCity : City<TBuilding>, new()
where TBuilding : Building, new()
{
TCity city = new TCity();
city.Buildings = new List<TBuilding>();
return city;
}




Ideally you could have a common baseclass for City and Building, because they share some significant properties like Id, Area and Name:



public abstract class AreaObject
{
public int Id { get; set; }
public string Name { get; set; }
public double Area { get; set; }
}


A complete refactoring of your data model could then be:



public abstract class AreaObject
{
public int Id { get; set; }
public string Name { get; set; }
public double Area { get; set; }
}

// For convenience a city base class without the generic type parameter:
public abstract class City : AreaObject
{
public abstract IEnumerable<Building> GetBuildings();
}

public class City<TBuilding> : City where TBuilding : Building
{
public IList<TBuilding> Buildings { get; set; }

public override IEnumerable<Building> GetBuildings()
{
return Buildings;
}
}

public class Building : AreaObject
{
public int Stories { get; set; }
}

public class MyBuilding : Building
{
public int MyId { get { return Id; } set { Id = value; } }
}

public class HisBuilding : Building
{
public int HisId { get { return Id; } set { Id = value; } }
}

public class MyCity : City<MyBuilding>
{
public int MyId { get { return Id; } set { Id = value; } }
}

public class HisCity : City<HisBuilding>
{
public int HisId { get { return Id; } set { Id = value; } }
}


It's a little odd to have two different sub cities having specialized buildings instead of just Buildings, but you may have reasons for that? (What if MyCity buys a building from HisCity can it then change from His to My?)






Here is the code I have for building the IEnumerable inside my
GetData method:



public static IEnumerable<TBuilding> GetBuildingData<TBuilding>()...




If that is going to be used inside GetData() shouldn't it then take a city id as argument in order to minimize the query? If so you can change the GetData to:



public static TCity CreateCity<TCity, TBuilding>(int id)
where TCity : City<TBuilding>, new()
where TBuilding : Building, new()
{
TCity city = new TCity();
city.Buildings = GetBuildingData<TBuilding>(id);
city.Id = id;
return city;
}


And you'll then have to modify your database query to only return the buildings for that city:



public static IList<TBuilding> GetBuildingData<TBuilding>(int cityId)
where TBuilding : Building, new() {...}




All in all this could simplify your use case to:



  int cityId = -1;
string strInput = Console.ReadLine();
int.TryParse(strInput, out cityId);
if (cityId > 0)
{
City city = null;

switch (cityId)
{
case 1:
city = CreateCity<MyCity, MyBuilding>(cityId);
break;
case 2:
city = CreateCity<HisCity, HisBuilding>(cityId);
break;
default:
throw new InvalidOperationException("Invalid Id");
}

string json = JsonConvert.SerializeObject(city, Formatting.Indented);
Console.WriteLine(json);
Console.ReadLine();
}





share|improve this answer











$endgroup$
















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "196"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f224040%2fcreating-custom-objects-with-custom-properties-using-generics%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    3












    $begingroup$

    I will focus on..




    Creating custom objects with custom properties using generics




    Which you do in this method..




    public static KeyValuePair<TCity, IEnumerable<TBuilding>> GetData<TCity, TBuilding>()
    where TCity : City, new()
    where TBuilding : Building, new()
    {
    TCity city = new TCity();
    IEnumerable<TBuilding> buildings = new List<TBuilding>();
    return new KeyValuePair<TCity, IEnumerable<TBuilding>>(city, buildings);
    }




    • A KeyValuePair is archaic, you can use a ValueTuple nowadays


    • TBuilding does not require the new() constraint in this method

    • The choice for IEnumerable over IList is questionable, since you retrieve the items later on and have no way of adding them to an IEnumerable. So why create the IEnumerable in this method?

    • The name should reflect what you are doing. CreateCity seems more appropriate.


    I would refactor this method..



    public static (TCity city, IList<TBuilding> buildings) CreateCity<TCity, TBuilding>()
    where TCity : City, new()
    where TBuilding : Building
    {
    var city = new TCity();
    var buildings = new List<TBuilding>();
    return (city, buildings);
    }


    EDIT:



    Thinking about the refactored method. This doesn't even need to be a method anymore. It doesn't do anything but create objects for the types you specify.



    What I would really do is throw out this ancient way of ORM, and use an existing API (EF, NHibernate, Dapper).






    share|improve this answer











    $endgroup$









    • 1




      $begingroup$
      I'm afraid we might here at some point this code is simplified, in my real code I actually do this and that :-
      $endgroup$
      – t3chb0t
      6 hours ago










    • $begingroup$
      When I refactor my method using the code you've posted, by replacing the KeyValuePair<TCity, IEnumerable<TBuilding>> with (TCity city, IList<TBuilding> buildings I just end up with a bunch of errors. Could this be because I'm using Visual Studio 2015?
      $endgroup$
      – Delfino
      6 hours ago






    • 1




      $begingroup$
      ValueTuple is supported since blogs.msdn.microsoft.com/mazhou/2017/05/26/…. You could keep using KeyValuePair instead, or use a regular Tuple.
      $endgroup$
      – dfhwze
      6 hours ago






    • 1




      $begingroup$
      ...about the ancient tools... it looks like you should add another one to this list and suggest using VS2019 :-P
      $endgroup$
      – t3chb0t
      5 hours ago


















    3












    $begingroup$

    I will focus on..




    Creating custom objects with custom properties using generics




    Which you do in this method..




    public static KeyValuePair<TCity, IEnumerable<TBuilding>> GetData<TCity, TBuilding>()
    where TCity : City, new()
    where TBuilding : Building, new()
    {
    TCity city = new TCity();
    IEnumerable<TBuilding> buildings = new List<TBuilding>();
    return new KeyValuePair<TCity, IEnumerable<TBuilding>>(city, buildings);
    }




    • A KeyValuePair is archaic, you can use a ValueTuple nowadays


    • TBuilding does not require the new() constraint in this method

    • The choice for IEnumerable over IList is questionable, since you retrieve the items later on and have no way of adding them to an IEnumerable. So why create the IEnumerable in this method?

    • The name should reflect what you are doing. CreateCity seems more appropriate.


    I would refactor this method..



    public static (TCity city, IList<TBuilding> buildings) CreateCity<TCity, TBuilding>()
    where TCity : City, new()
    where TBuilding : Building
    {
    var city = new TCity();
    var buildings = new List<TBuilding>();
    return (city, buildings);
    }


    EDIT:



    Thinking about the refactored method. This doesn't even need to be a method anymore. It doesn't do anything but create objects for the types you specify.



    What I would really do is throw out this ancient way of ORM, and use an existing API (EF, NHibernate, Dapper).






    share|improve this answer











    $endgroup$









    • 1




      $begingroup$
      I'm afraid we might here at some point this code is simplified, in my real code I actually do this and that :-
      $endgroup$
      – t3chb0t
      6 hours ago










    • $begingroup$
      When I refactor my method using the code you've posted, by replacing the KeyValuePair<TCity, IEnumerable<TBuilding>> with (TCity city, IList<TBuilding> buildings I just end up with a bunch of errors. Could this be because I'm using Visual Studio 2015?
      $endgroup$
      – Delfino
      6 hours ago






    • 1




      $begingroup$
      ValueTuple is supported since blogs.msdn.microsoft.com/mazhou/2017/05/26/…. You could keep using KeyValuePair instead, or use a regular Tuple.
      $endgroup$
      – dfhwze
      6 hours ago






    • 1




      $begingroup$
      ...about the ancient tools... it looks like you should add another one to this list and suggest using VS2019 :-P
      $endgroup$
      – t3chb0t
      5 hours ago
















    3












    3








    3





    $begingroup$

    I will focus on..




    Creating custom objects with custom properties using generics




    Which you do in this method..




    public static KeyValuePair<TCity, IEnumerable<TBuilding>> GetData<TCity, TBuilding>()
    where TCity : City, new()
    where TBuilding : Building, new()
    {
    TCity city = new TCity();
    IEnumerable<TBuilding> buildings = new List<TBuilding>();
    return new KeyValuePair<TCity, IEnumerable<TBuilding>>(city, buildings);
    }




    • A KeyValuePair is archaic, you can use a ValueTuple nowadays


    • TBuilding does not require the new() constraint in this method

    • The choice for IEnumerable over IList is questionable, since you retrieve the items later on and have no way of adding them to an IEnumerable. So why create the IEnumerable in this method?

    • The name should reflect what you are doing. CreateCity seems more appropriate.


    I would refactor this method..



    public static (TCity city, IList<TBuilding> buildings) CreateCity<TCity, TBuilding>()
    where TCity : City, new()
    where TBuilding : Building
    {
    var city = new TCity();
    var buildings = new List<TBuilding>();
    return (city, buildings);
    }


    EDIT:



    Thinking about the refactored method. This doesn't even need to be a method anymore. It doesn't do anything but create objects for the types you specify.



    What I would really do is throw out this ancient way of ORM, and use an existing API (EF, NHibernate, Dapper).






    share|improve this answer











    $endgroup$



    I will focus on..




    Creating custom objects with custom properties using generics




    Which you do in this method..




    public static KeyValuePair<TCity, IEnumerable<TBuilding>> GetData<TCity, TBuilding>()
    where TCity : City, new()
    where TBuilding : Building, new()
    {
    TCity city = new TCity();
    IEnumerable<TBuilding> buildings = new List<TBuilding>();
    return new KeyValuePair<TCity, IEnumerable<TBuilding>>(city, buildings);
    }




    • A KeyValuePair is archaic, you can use a ValueTuple nowadays


    • TBuilding does not require the new() constraint in this method

    • The choice for IEnumerable over IList is questionable, since you retrieve the items later on and have no way of adding them to an IEnumerable. So why create the IEnumerable in this method?

    • The name should reflect what you are doing. CreateCity seems more appropriate.


    I would refactor this method..



    public static (TCity city, IList<TBuilding> buildings) CreateCity<TCity, TBuilding>()
    where TCity : City, new()
    where TBuilding : Building
    {
    var city = new TCity();
    var buildings = new List<TBuilding>();
    return (city, buildings);
    }


    EDIT:



    Thinking about the refactored method. This doesn't even need to be a method anymore. It doesn't do anything but create objects for the types you specify.



    What I would really do is throw out this ancient way of ORM, and use an existing API (EF, NHibernate, Dapper).







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 6 hours ago

























    answered 6 hours ago









    dfhwzedfhwze

    4,4601 gold badge7 silver badges34 bronze badges




    4,4601 gold badge7 silver badges34 bronze badges








    • 1




      $begingroup$
      I'm afraid we might here at some point this code is simplified, in my real code I actually do this and that :-
      $endgroup$
      – t3chb0t
      6 hours ago










    • $begingroup$
      When I refactor my method using the code you've posted, by replacing the KeyValuePair<TCity, IEnumerable<TBuilding>> with (TCity city, IList<TBuilding> buildings I just end up with a bunch of errors. Could this be because I'm using Visual Studio 2015?
      $endgroup$
      – Delfino
      6 hours ago






    • 1




      $begingroup$
      ValueTuple is supported since blogs.msdn.microsoft.com/mazhou/2017/05/26/…. You could keep using KeyValuePair instead, or use a regular Tuple.
      $endgroup$
      – dfhwze
      6 hours ago






    • 1




      $begingroup$
      ...about the ancient tools... it looks like you should add another one to this list and suggest using VS2019 :-P
      $endgroup$
      – t3chb0t
      5 hours ago
















    • 1




      $begingroup$
      I'm afraid we might here at some point this code is simplified, in my real code I actually do this and that :-
      $endgroup$
      – t3chb0t
      6 hours ago










    • $begingroup$
      When I refactor my method using the code you've posted, by replacing the KeyValuePair<TCity, IEnumerable<TBuilding>> with (TCity city, IList<TBuilding> buildings I just end up with a bunch of errors. Could this be because I'm using Visual Studio 2015?
      $endgroup$
      – Delfino
      6 hours ago






    • 1




      $begingroup$
      ValueTuple is supported since blogs.msdn.microsoft.com/mazhou/2017/05/26/…. You could keep using KeyValuePair instead, or use a regular Tuple.
      $endgroup$
      – dfhwze
      6 hours ago






    • 1




      $begingroup$
      ...about the ancient tools... it looks like you should add another one to this list and suggest using VS2019 :-P
      $endgroup$
      – t3chb0t
      5 hours ago










    1




    1




    $begingroup$
    I'm afraid we might here at some point this code is simplified, in my real code I actually do this and that :-
    $endgroup$
    – t3chb0t
    6 hours ago




    $begingroup$
    I'm afraid we might here at some point this code is simplified, in my real code I actually do this and that :-
    $endgroup$
    – t3chb0t
    6 hours ago












    $begingroup$
    When I refactor my method using the code you've posted, by replacing the KeyValuePair<TCity, IEnumerable<TBuilding>> with (TCity city, IList<TBuilding> buildings I just end up with a bunch of errors. Could this be because I'm using Visual Studio 2015?
    $endgroup$
    – Delfino
    6 hours ago




    $begingroup$
    When I refactor my method using the code you've posted, by replacing the KeyValuePair<TCity, IEnumerable<TBuilding>> with (TCity city, IList<TBuilding> buildings I just end up with a bunch of errors. Could this be because I'm using Visual Studio 2015?
    $endgroup$
    – Delfino
    6 hours ago




    1




    1




    $begingroup$
    ValueTuple is supported since blogs.msdn.microsoft.com/mazhou/2017/05/26/…. You could keep using KeyValuePair instead, or use a regular Tuple.
    $endgroup$
    – dfhwze
    6 hours ago




    $begingroup$
    ValueTuple is supported since blogs.msdn.microsoft.com/mazhou/2017/05/26/…. You could keep using KeyValuePair instead, or use a regular Tuple.
    $endgroup$
    – dfhwze
    6 hours ago




    1




    1




    $begingroup$
    ...about the ancient tools... it looks like you should add another one to this list and suggest using VS2019 :-P
    $endgroup$
    – t3chb0t
    5 hours ago






    $begingroup$
    ...about the ancient tools... it looks like you should add another one to this list and suggest using VS2019 :-P
    $endgroup$
    – t3chb0t
    5 hours ago















    2












    $begingroup$


    public class MyBuilding : Building
    {
    public int MyId { get; set; }
    }

    public class HisBuilding : Building
    {
    public int HisId { get; set; }
    }



    Why do you have the id as properties of the subclasses, it's a candidate for a base class member:



    public class Building
    {
    public int Id { get; set; }


    If the subclasses must have specialized names for their Id property, then provide that as:



    public class MyBuilding : Building
    {
    public int MyId { get { return Id; } set { Id = value; } }
    }


    but that is a rather odd concept that you should avoid if possible.



    The same holds for Cities.





    public class MyCity : City
    {
    public int MyId { get; set; }
    public IEnumerable<MyBuilding> Buildings { get; set; }
    }


    Normally you would have a materialized data set for buildings instead of an IEnumerable<T> - unless you're creating the instances lazily/dynamically. You could maybe consider using a IReadonlyList<T> as type, if you don't want it to be modifiable or else just a IList<T>






    public static KeyValuePair<TCity, IEnumerable<TBuilding>> GetData<TCity, TBuilding>()
    where TCity : City, new()
    where TBuilding : Building, new()
    {
    TCity city = new TCity();
    IEnumerable<TBuilding> buildings = new List<TBuilding>();
    return new KeyValuePair<TCity, IEnumerable<TBuilding>>(city, buildings);
    }



    If you changed the City base class to a generic like:



    public class City<TBuilding> where TBuilding: Building
    {
    public IList<TBuilding> Buildings { get; set; }
    }


    and dropped the buildings on the specialized cities, then you could return just the city from GetData, because you can initialize the Buildings property inside GetData, which I would rename to CreateCity()



    public static TCity CreateCity<TCity, TBuilding>()
    where TCity : City<TBuilding>, new()
    where TBuilding : Building, new()
    {
    TCity city = new TCity();
    city.Buildings = new List<TBuilding>();
    return city;
    }




    Ideally you could have a common baseclass for City and Building, because they share some significant properties like Id, Area and Name:



    public abstract class AreaObject
    {
    public int Id { get; set; }
    public string Name { get; set; }
    public double Area { get; set; }
    }


    A complete refactoring of your data model could then be:



    public abstract class AreaObject
    {
    public int Id { get; set; }
    public string Name { get; set; }
    public double Area { get; set; }
    }

    // For convenience a city base class without the generic type parameter:
    public abstract class City : AreaObject
    {
    public abstract IEnumerable<Building> GetBuildings();
    }

    public class City<TBuilding> : City where TBuilding : Building
    {
    public IList<TBuilding> Buildings { get; set; }

    public override IEnumerable<Building> GetBuildings()
    {
    return Buildings;
    }
    }

    public class Building : AreaObject
    {
    public int Stories { get; set; }
    }

    public class MyBuilding : Building
    {
    public int MyId { get { return Id; } set { Id = value; } }
    }

    public class HisBuilding : Building
    {
    public int HisId { get { return Id; } set { Id = value; } }
    }

    public class MyCity : City<MyBuilding>
    {
    public int MyId { get { return Id; } set { Id = value; } }
    }

    public class HisCity : City<HisBuilding>
    {
    public int HisId { get { return Id; } set { Id = value; } }
    }


    It's a little odd to have two different sub cities having specialized buildings instead of just Buildings, but you may have reasons for that? (What if MyCity buys a building from HisCity can it then change from His to My?)






    Here is the code I have for building the IEnumerable inside my
    GetData method:



    public static IEnumerable<TBuilding> GetBuildingData<TBuilding>()...




    If that is going to be used inside GetData() shouldn't it then take a city id as argument in order to minimize the query? If so you can change the GetData to:



    public static TCity CreateCity<TCity, TBuilding>(int id)
    where TCity : City<TBuilding>, new()
    where TBuilding : Building, new()
    {
    TCity city = new TCity();
    city.Buildings = GetBuildingData<TBuilding>(id);
    city.Id = id;
    return city;
    }


    And you'll then have to modify your database query to only return the buildings for that city:



    public static IList<TBuilding> GetBuildingData<TBuilding>(int cityId)
    where TBuilding : Building, new() {...}




    All in all this could simplify your use case to:



      int cityId = -1;
    string strInput = Console.ReadLine();
    int.TryParse(strInput, out cityId);
    if (cityId > 0)
    {
    City city = null;

    switch (cityId)
    {
    case 1:
    city = CreateCity<MyCity, MyBuilding>(cityId);
    break;
    case 2:
    city = CreateCity<HisCity, HisBuilding>(cityId);
    break;
    default:
    throw new InvalidOperationException("Invalid Id");
    }

    string json = JsonConvert.SerializeObject(city, Formatting.Indented);
    Console.WriteLine(json);
    Console.ReadLine();
    }





    share|improve this answer











    $endgroup$


















      2












      $begingroup$


      public class MyBuilding : Building
      {
      public int MyId { get; set; }
      }

      public class HisBuilding : Building
      {
      public int HisId { get; set; }
      }



      Why do you have the id as properties of the subclasses, it's a candidate for a base class member:



      public class Building
      {
      public int Id { get; set; }


      If the subclasses must have specialized names for their Id property, then provide that as:



      public class MyBuilding : Building
      {
      public int MyId { get { return Id; } set { Id = value; } }
      }


      but that is a rather odd concept that you should avoid if possible.



      The same holds for Cities.





      public class MyCity : City
      {
      public int MyId { get; set; }
      public IEnumerable<MyBuilding> Buildings { get; set; }
      }


      Normally you would have a materialized data set for buildings instead of an IEnumerable<T> - unless you're creating the instances lazily/dynamically. You could maybe consider using a IReadonlyList<T> as type, if you don't want it to be modifiable or else just a IList<T>






      public static KeyValuePair<TCity, IEnumerable<TBuilding>> GetData<TCity, TBuilding>()
      where TCity : City, new()
      where TBuilding : Building, new()
      {
      TCity city = new TCity();
      IEnumerable<TBuilding> buildings = new List<TBuilding>();
      return new KeyValuePair<TCity, IEnumerable<TBuilding>>(city, buildings);
      }



      If you changed the City base class to a generic like:



      public class City<TBuilding> where TBuilding: Building
      {
      public IList<TBuilding> Buildings { get; set; }
      }


      and dropped the buildings on the specialized cities, then you could return just the city from GetData, because you can initialize the Buildings property inside GetData, which I would rename to CreateCity()



      public static TCity CreateCity<TCity, TBuilding>()
      where TCity : City<TBuilding>, new()
      where TBuilding : Building, new()
      {
      TCity city = new TCity();
      city.Buildings = new List<TBuilding>();
      return city;
      }




      Ideally you could have a common baseclass for City and Building, because they share some significant properties like Id, Area and Name:



      public abstract class AreaObject
      {
      public int Id { get; set; }
      public string Name { get; set; }
      public double Area { get; set; }
      }


      A complete refactoring of your data model could then be:



      public abstract class AreaObject
      {
      public int Id { get; set; }
      public string Name { get; set; }
      public double Area { get; set; }
      }

      // For convenience a city base class without the generic type parameter:
      public abstract class City : AreaObject
      {
      public abstract IEnumerable<Building> GetBuildings();
      }

      public class City<TBuilding> : City where TBuilding : Building
      {
      public IList<TBuilding> Buildings { get; set; }

      public override IEnumerable<Building> GetBuildings()
      {
      return Buildings;
      }
      }

      public class Building : AreaObject
      {
      public int Stories { get; set; }
      }

      public class MyBuilding : Building
      {
      public int MyId { get { return Id; } set { Id = value; } }
      }

      public class HisBuilding : Building
      {
      public int HisId { get { return Id; } set { Id = value; } }
      }

      public class MyCity : City<MyBuilding>
      {
      public int MyId { get { return Id; } set { Id = value; } }
      }

      public class HisCity : City<HisBuilding>
      {
      public int HisId { get { return Id; } set { Id = value; } }
      }


      It's a little odd to have two different sub cities having specialized buildings instead of just Buildings, but you may have reasons for that? (What if MyCity buys a building from HisCity can it then change from His to My?)






      Here is the code I have for building the IEnumerable inside my
      GetData method:



      public static IEnumerable<TBuilding> GetBuildingData<TBuilding>()...




      If that is going to be used inside GetData() shouldn't it then take a city id as argument in order to minimize the query? If so you can change the GetData to:



      public static TCity CreateCity<TCity, TBuilding>(int id)
      where TCity : City<TBuilding>, new()
      where TBuilding : Building, new()
      {
      TCity city = new TCity();
      city.Buildings = GetBuildingData<TBuilding>(id);
      city.Id = id;
      return city;
      }


      And you'll then have to modify your database query to only return the buildings for that city:



      public static IList<TBuilding> GetBuildingData<TBuilding>(int cityId)
      where TBuilding : Building, new() {...}




      All in all this could simplify your use case to:



        int cityId = -1;
      string strInput = Console.ReadLine();
      int.TryParse(strInput, out cityId);
      if (cityId > 0)
      {
      City city = null;

      switch (cityId)
      {
      case 1:
      city = CreateCity<MyCity, MyBuilding>(cityId);
      break;
      case 2:
      city = CreateCity<HisCity, HisBuilding>(cityId);
      break;
      default:
      throw new InvalidOperationException("Invalid Id");
      }

      string json = JsonConvert.SerializeObject(city, Formatting.Indented);
      Console.WriteLine(json);
      Console.ReadLine();
      }





      share|improve this answer











      $endgroup$
















        2












        2








        2





        $begingroup$


        public class MyBuilding : Building
        {
        public int MyId { get; set; }
        }

        public class HisBuilding : Building
        {
        public int HisId { get; set; }
        }



        Why do you have the id as properties of the subclasses, it's a candidate for a base class member:



        public class Building
        {
        public int Id { get; set; }


        If the subclasses must have specialized names for their Id property, then provide that as:



        public class MyBuilding : Building
        {
        public int MyId { get { return Id; } set { Id = value; } }
        }


        but that is a rather odd concept that you should avoid if possible.



        The same holds for Cities.





        public class MyCity : City
        {
        public int MyId { get; set; }
        public IEnumerable<MyBuilding> Buildings { get; set; }
        }


        Normally you would have a materialized data set for buildings instead of an IEnumerable<T> - unless you're creating the instances lazily/dynamically. You could maybe consider using a IReadonlyList<T> as type, if you don't want it to be modifiable or else just a IList<T>






        public static KeyValuePair<TCity, IEnumerable<TBuilding>> GetData<TCity, TBuilding>()
        where TCity : City, new()
        where TBuilding : Building, new()
        {
        TCity city = new TCity();
        IEnumerable<TBuilding> buildings = new List<TBuilding>();
        return new KeyValuePair<TCity, IEnumerable<TBuilding>>(city, buildings);
        }



        If you changed the City base class to a generic like:



        public class City<TBuilding> where TBuilding: Building
        {
        public IList<TBuilding> Buildings { get; set; }
        }


        and dropped the buildings on the specialized cities, then you could return just the city from GetData, because you can initialize the Buildings property inside GetData, which I would rename to CreateCity()



        public static TCity CreateCity<TCity, TBuilding>()
        where TCity : City<TBuilding>, new()
        where TBuilding : Building, new()
        {
        TCity city = new TCity();
        city.Buildings = new List<TBuilding>();
        return city;
        }




        Ideally you could have a common baseclass for City and Building, because they share some significant properties like Id, Area and Name:



        public abstract class AreaObject
        {
        public int Id { get; set; }
        public string Name { get; set; }
        public double Area { get; set; }
        }


        A complete refactoring of your data model could then be:



        public abstract class AreaObject
        {
        public int Id { get; set; }
        public string Name { get; set; }
        public double Area { get; set; }
        }

        // For convenience a city base class without the generic type parameter:
        public abstract class City : AreaObject
        {
        public abstract IEnumerable<Building> GetBuildings();
        }

        public class City<TBuilding> : City where TBuilding : Building
        {
        public IList<TBuilding> Buildings { get; set; }

        public override IEnumerable<Building> GetBuildings()
        {
        return Buildings;
        }
        }

        public class Building : AreaObject
        {
        public int Stories { get; set; }
        }

        public class MyBuilding : Building
        {
        public int MyId { get { return Id; } set { Id = value; } }
        }

        public class HisBuilding : Building
        {
        public int HisId { get { return Id; } set { Id = value; } }
        }

        public class MyCity : City<MyBuilding>
        {
        public int MyId { get { return Id; } set { Id = value; } }
        }

        public class HisCity : City<HisBuilding>
        {
        public int HisId { get { return Id; } set { Id = value; } }
        }


        It's a little odd to have two different sub cities having specialized buildings instead of just Buildings, but you may have reasons for that? (What if MyCity buys a building from HisCity can it then change from His to My?)






        Here is the code I have for building the IEnumerable inside my
        GetData method:



        public static IEnumerable<TBuilding> GetBuildingData<TBuilding>()...




        If that is going to be used inside GetData() shouldn't it then take a city id as argument in order to minimize the query? If so you can change the GetData to:



        public static TCity CreateCity<TCity, TBuilding>(int id)
        where TCity : City<TBuilding>, new()
        where TBuilding : Building, new()
        {
        TCity city = new TCity();
        city.Buildings = GetBuildingData<TBuilding>(id);
        city.Id = id;
        return city;
        }


        And you'll then have to modify your database query to only return the buildings for that city:



        public static IList<TBuilding> GetBuildingData<TBuilding>(int cityId)
        where TBuilding : Building, new() {...}




        All in all this could simplify your use case to:



          int cityId = -1;
        string strInput = Console.ReadLine();
        int.TryParse(strInput, out cityId);
        if (cityId > 0)
        {
        City city = null;

        switch (cityId)
        {
        case 1:
        city = CreateCity<MyCity, MyBuilding>(cityId);
        break;
        case 2:
        city = CreateCity<HisCity, HisBuilding>(cityId);
        break;
        default:
        throw new InvalidOperationException("Invalid Id");
        }

        string json = JsonConvert.SerializeObject(city, Formatting.Indented);
        Console.WriteLine(json);
        Console.ReadLine();
        }





        share|improve this answer











        $endgroup$




        public class MyBuilding : Building
        {
        public int MyId { get; set; }
        }

        public class HisBuilding : Building
        {
        public int HisId { get; set; }
        }



        Why do you have the id as properties of the subclasses, it's a candidate for a base class member:



        public class Building
        {
        public int Id { get; set; }


        If the subclasses must have specialized names for their Id property, then provide that as:



        public class MyBuilding : Building
        {
        public int MyId { get { return Id; } set { Id = value; } }
        }


        but that is a rather odd concept that you should avoid if possible.



        The same holds for Cities.





        public class MyCity : City
        {
        public int MyId { get; set; }
        public IEnumerable<MyBuilding> Buildings { get; set; }
        }


        Normally you would have a materialized data set for buildings instead of an IEnumerable<T> - unless you're creating the instances lazily/dynamically. You could maybe consider using a IReadonlyList<T> as type, if you don't want it to be modifiable or else just a IList<T>






        public static KeyValuePair<TCity, IEnumerable<TBuilding>> GetData<TCity, TBuilding>()
        where TCity : City, new()
        where TBuilding : Building, new()
        {
        TCity city = new TCity();
        IEnumerable<TBuilding> buildings = new List<TBuilding>();
        return new KeyValuePair<TCity, IEnumerable<TBuilding>>(city, buildings);
        }



        If you changed the City base class to a generic like:



        public class City<TBuilding> where TBuilding: Building
        {
        public IList<TBuilding> Buildings { get; set; }
        }


        and dropped the buildings on the specialized cities, then you could return just the city from GetData, because you can initialize the Buildings property inside GetData, which I would rename to CreateCity()



        public static TCity CreateCity<TCity, TBuilding>()
        where TCity : City<TBuilding>, new()
        where TBuilding : Building, new()
        {
        TCity city = new TCity();
        city.Buildings = new List<TBuilding>();
        return city;
        }




        Ideally you could have a common baseclass for City and Building, because they share some significant properties like Id, Area and Name:



        public abstract class AreaObject
        {
        public int Id { get; set; }
        public string Name { get; set; }
        public double Area { get; set; }
        }


        A complete refactoring of your data model could then be:



        public abstract class AreaObject
        {
        public int Id { get; set; }
        public string Name { get; set; }
        public double Area { get; set; }
        }

        // For convenience a city base class without the generic type parameter:
        public abstract class City : AreaObject
        {
        public abstract IEnumerable<Building> GetBuildings();
        }

        public class City<TBuilding> : City where TBuilding : Building
        {
        public IList<TBuilding> Buildings { get; set; }

        public override IEnumerable<Building> GetBuildings()
        {
        return Buildings;
        }
        }

        public class Building : AreaObject
        {
        public int Stories { get; set; }
        }

        public class MyBuilding : Building
        {
        public int MyId { get { return Id; } set { Id = value; } }
        }

        public class HisBuilding : Building
        {
        public int HisId { get { return Id; } set { Id = value; } }
        }

        public class MyCity : City<MyBuilding>
        {
        public int MyId { get { return Id; } set { Id = value; } }
        }

        public class HisCity : City<HisBuilding>
        {
        public int HisId { get { return Id; } set { Id = value; } }
        }


        It's a little odd to have two different sub cities having specialized buildings instead of just Buildings, but you may have reasons for that? (What if MyCity buys a building from HisCity can it then change from His to My?)






        Here is the code I have for building the IEnumerable inside my
        GetData method:



        public static IEnumerable<TBuilding> GetBuildingData<TBuilding>()...




        If that is going to be used inside GetData() shouldn't it then take a city id as argument in order to minimize the query? If so you can change the GetData to:



        public static TCity CreateCity<TCity, TBuilding>(int id)
        where TCity : City<TBuilding>, new()
        where TBuilding : Building, new()
        {
        TCity city = new TCity();
        city.Buildings = GetBuildingData<TBuilding>(id);
        city.Id = id;
        return city;
        }


        And you'll then have to modify your database query to only return the buildings for that city:



        public static IList<TBuilding> GetBuildingData<TBuilding>(int cityId)
        where TBuilding : Building, new() {...}




        All in all this could simplify your use case to:



          int cityId = -1;
        string strInput = Console.ReadLine();
        int.TryParse(strInput, out cityId);
        if (cityId > 0)
        {
        City city = null;

        switch (cityId)
        {
        case 1:
        city = CreateCity<MyCity, MyBuilding>(cityId);
        break;
        case 2:
        city = CreateCity<HisCity, HisBuilding>(cityId);
        break;
        default:
        throw new InvalidOperationException("Invalid Id");
        }

        string json = JsonConvert.SerializeObject(city, Formatting.Indented);
        Console.WriteLine(json);
        Console.ReadLine();
        }






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 4 hours ago

























        answered 5 hours ago









        Henrik HansenHenrik Hansen

        10.5k1 gold badge13 silver badges38 bronze badges




        10.5k1 gold badge13 silver badges38 bronze badges






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Code Review Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            Use MathJax to format equations. MathJax reference.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f224040%2fcreating-custom-objects-with-custom-properties-using-generics%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Hudson River Historic District Contents Geography History The district today Aesthetics Cultural...

            The number designs the writing. Feandra Aversely Definition: The act of ingrafting a sprig or shoot of one...

            Ayherre Geografie Demografie Externe links Navigatiemenu43° 23′ NB, 1° 15′ WL43° 23′ NB, 1°...