Generic classes and its child - c#

I have base class Entity and an enheritance class say Home ,
public class Home : Entity
{
public int CityId{get;set;}
}
public class Town : Entity
{
public int CityId {get;set}
public Home CityHall {get;set;}
public List<Home > Homes{get;set;}
}
I want to set the CityId for Town and its children
so a first try I did the following
public class DataAccessBase<T> where T : Entity
{
public int Add(T entity)
{
Type t = typeof(T);
PropertyInfo prop = t.GetProperty("CityId");
if (prop != null)
{
prop.SetValue(entity, 2);
}
}
}
this work only for the parent how to access children , I want to d othat generically simply because I have a dataaaccesslayer that insert of Database genrically

It looks like there are two unrelated problems
how to set property of an object without knowledge if property is there: reflection as you have it solve that. Note that this is not very C# way - you'd use some interface and restrict generics to that interface to allow strongly typed access to properties.
how to enumerate "child" objects without knowing type: traditional solution again is to add interface for "GetChildren" functionality. Alternatively you can go with reflection and find all properties that are of "child" type and combine with all properties that are of type IEnumerable<"child type">.
If you can use some convention dynamic could be easier alternative to reflection (i.e. every type exposes Children property to enumerate them:
dynamic town = GetTown();
foreach(dynamic child in town.Children) {...}

You can set the properties directly no need for reflection.
entity.CityId = 1;
if(entity is Town) {
var town = entity as Town;
if(town.Homes!=null) {
town.Homes.ForEach(t=> t.CityId = entity.CityId);
}
}

Related

Let class have unique id which doesn't ever change, no matter what

I have classes that might or might not change their name (and members) during development. My classes are used (in most cases) like enums, but I couldn't use enums because I needed slightly more functionality. Since classes (obviously) don't have an Integer representing them under the surface I need to create some solution for having similar functionality. In other words, I want for each class to be represented by an Integer (or some other unique identifier).
I've created this attribute:
public class IdAttribute : Attribute
{
private int id = -1;
public IdAttribute(int index)
{
this.id = index;
}
public int Id
{
get
{
return id;
}
}
}
And I'm using it as following:
[Id(0)]
public class Hello: Core { }
[Id(1)]
public class Bye: Core { }
As you can see it's quite error prone, since I don't want any class to have the same Id. And thus, optimally I want an automatic generated id, but I don't want it to change if I ever change anything regarding the class, for example the class name or its members.
What's the best way to achieve this?
(I know that in Java, that once you make a class Serializable, you'll get an automatically generated id (is there something like this in C#?).)
EDIT:
The reason I "couldn't" just use enums is because of (mainly) convenience. I have classes which exposes fields in an editor. And in this editor I can select only the appropriate "enums", in some cases only enums which inherits from "Core" will be displayed and in other cases they might inherit from "Tools" or some other class. I hope that cleared up a bit.
Not sure why you'd need to do this, but you could do the following:
[AttributeUsage(AttributeTargets.Class)]
public class IdAttribute:Attribute
{
public Guid Id { get; }
public IdAttribute(string id)
{
Id = new Guid(id);
}
}
And you'd use it like:
[IdAttribute("7d7952d1-86df-4e2e-b040-fed335aad775")]
public class SomeClass
{
//example, you'd obviously cache this
public Guid Id => GetType().GetCustomAttribute<IdAttribute>().Id;
//...
}
Do note, that Guids are not random. If you need a random id, then this isn't the solution. To generate a Guid read comments to your question.
You can handle that through your base class Core:
public abstract class Core
{
public Core()
{
Type myType = this.GetType();
object[] attrs = myType.GetCustomAttributes(typeof(IdAttribute), false);
IdAttribute attr = attrs?.OfType<IdAttribute>().FirstOrDefault();
int id = -1;
if (attr != null) id = attr.Id;
if (!reservedIdentities.ContainsKey(id))
{
reservedIdentities.Add(id, myType);
}
else
{
if (!reservedIdentities[id].Equals(myType))
throw new ArgumentException("Duplicate identities discovered.", nameof(id));
}
}
static Dictionary<int, Type> reservedIdentities = new Dictionary<int, Type>();
//...
}

Creating common class objects based on class name and use it

I have the same code logic used across different class objects.
For ex:
var matchingTypes = from matchType in order.Contacts
select matchType;
var matchingTypes = from matchType in customer.Contacts
select matchType;
Instead of writing duplicate lines of code, i would like to pass order, customer class names and get Contacts through it, so that the above code will look like (we are using LINQ in our code)
var matchingTypes = from matchType in objectElement.Contacts
select matchType;
The stuff i tried is passed an object parameter
GetData(object objectElement) // method consuming an object parameter.
var objectOrder= objectElement as Orders;
var objectCustomer= objectElement as Customers;
if(objectOrder!=null)
{
objectElement = (Orders) objectOrder; //type
}
if(objectCustomer !=null)
{
objectElement = (Customers) objectCustomer;
}
By doing so, i am repeating my code, which i would like to avoid, any suggestions/ideas? thanks.
I would like to use objectElement and assign only once, so that i can call like this as shown below
var matchingTypes = from matchType in objectElement.Contacts
select matchType;
An interface would be the preferred way to do this, but you could also use dynamic to duck type a method:
public IEnumerable<Contact> GetContacts(dynamic yourObject)
{
return yourObject.Contacts;
}
Note this will not give you a compile error if you call it with something that doesn't have a property called Contacts of type IEnumerable<Contact> but will instead give you a runtime error.
Or you don't even actually need a method, you could just do this:
var matchedTypes = ((dynamic)yourObject).Contacts as IEnumerable<Contact>;
Interfaces would be a safer bet, but are a little tricky with generate entity framework classes. But you can do them becuase they are generated as partial classes. So you can do something like this:
public interface IHaveContacts
{
public IEnumerable<Contact> Contacts { get; }
}
and then:
public partial class Orders : IHaveContacts
{
// should need to do anything since the auto-genrated Contacts property
// will satisfy the interface
}
public partial class Customers : IHaveContacts
{
// ditto
}
And now you can do:
var matchedTypes = ((IHaveContacts)yourObject).Contacts;
Or, if you really, really must (which you don't):
var matchedTypes = from matchType in ((IHaveContacts)yourObject).Contacts
select matchType;
Create an interface IContactsContainer:
public interface IContactsContainer
{
public YourContactType Contacts{get;set;}
}
Then your customer and order classes can implement it:
public class Customers : IContactsContainer
{
public YourContactType Contacts {get;set;}
....
}
public class Orders: IContactsContainer
{
public YourContactType Contacts {get;set;}
....
}
After that in your method you can use:
IContactsContainer objectElement = yourOrderObject;

Reflection in WinRt getting parameter of an inherited class

I got two classes, and i want to use reflection.
public Class A
{
public string aa { get; set; }
public string bb { get; set; }
...
}
public Class B: A {}
when i try to get the Property of an B object i got no properties;
TypeInfo b = typeof(B).GetTypeInfo();
IEnumerable<PropertyInfo> pList = b.DeclaredProperties;
pList is always null, maybe because i used "DeclaredProperties" instead of GetProproperties(), but in winRt i can't use it.
i've read this solution How to get properties of a class in WinRT but i can't use var properties = this.GetType().GetTypeInfo().GetRuntimeProperties(); because GetRuntimeProperties() is not recognized
Solution Found, doubts still remain
To get the property of an inherited class i need to get the RuntimeProperties in this way
IEnumerable<PropertyInfo> pList = typeof(B).GetRuntimeProperties();
ignoring the PropertyInfo, and it works too if i try to get the property of an A object
What are the differences between getType().GetTypeInfo() and getType().GetRuntimeProperties() while i'm reading the property of an A object?
public string aa;
public string bb;
These are not properties. Properties are defined such as:
public string Aa
{
get;
set;
}
For more information, look up the official documentation on MSDN.
Once you've made the corrections to your classes A and B, you will be able to use :
var classProperties = typeof(B).GetTypeInfo().DeclaredProperties;
For properties defined within the class B, and :
var allProperties = typeof(B).GetRuntimeProperties();
For properties that are defined within the class and in its inheritance tree; i.e. properties that are actually accessible at runtime (therefore the name of the method).
If you don't want to change the public fields to properties (but you definitely should), use the GetRuntimeFields method on typeof(B) and DeclaredMembers on typeof(B).GetTypeInfo() for similar behaviour.

Generic method using Linq and inheritance to bind to object

I'm struggling to get my head around how to do the following:
I have several methods that return different strongly-typed IEnumerable objects.
These strongly-typed class share a common base class that exposes properties I want to access in a Linq selector.
However I can't seem to get this working. If I just pass the base type in the method then I get errors when binding the IEnumerable because the properties available in the derived class are not available.
If I try to pass the type then because the Linq expression does not know the type I can't access the properties that I need in my Linq expression.
I need to somehow tell the Linq expression that my IEnumerable of type is derived from my base class.
Below is an example of what I'm trying to do:
private IEnumerable<MyStronglyTypedResultSet> GetReportDetails()
{
// this returns the IEnumerable of the derived type
}
public class MyBaseClass
{
public Guid UserId {get; set;}
public string OfficeName {get; set;}
}
public class MyStronglyTypedResultSet : MyBaseClass
{
public string FullName {get; set;}
public int Age {get; set;}
}
public void MyProblemMethod<T>(IEnumerable<T> allData, string officeToFind)
{
// How do I tell Linq that my <T> type is derived from 'MyBaseClass' so I can access the 'OfficeName' property?
IEnumerable<T> myData = allData.Where(c => c.OfficeName .ToLower().Equals(officeToFind.ToLower()));
MyUsefulObject.DataSource= myData; // This needs to have access to the properties in 'MyStronglyTypedResultSet'
MyUsefulObject.DataaBind();
}
You can use the OfType extension method.
public void MyProblemMethod<T>(IEnumerable<T> allData, string officeToFind)
{
// How do I tell Linq that my <T> type is derived from 'MyBaseClass' so I can access the 'OfficeName' property?
IEnumerable<T> myData = allData.OfType<MyBaseClass>.Where(c => c.OfficeName .ToLower().Equals(officeToFind.ToLower()));
MyUsefulObject.DataSource= myData;
MyUsefulObject.DataaBind();
}
Change your method like below
public void MyProblemMethod<T>(IEnumerable<T> allData, string officeToFind) where T : MyBaseClass
{
// How do I tell Linq that my <T> type is derived from 'MyBaseClass' so I can access the 'OfficeName' property?
IEnumerable<T> myData = allData.Where(c => c.OfficeName .ToLower().Equals(officeToFind.ToLower()));
MyUsefulObject.DataSource= myData; // This needs to have access to the properties in 'MyStronglyTypedResultSet'
MyUsefulObject.DataaBind();
}

Enumerate ICollection<T> property of class using Reflection

I'm trying to create a base class for my POCO objects in .NET 4, which will have an Include(string path) method, where path is a "." delimited navigation path of nested ICollection properties of the inheriting class to be enumerated.
For example, given the following classes;
public class Region
{
public string Name { get; set; }
public ICollection<Country> Countries { get; set; }
}
public partial class Region : EntityBase<Region> {}
public class Country
{
public string Name { get; set; }
public ICollection<City> Cities { get; set; }
}
public partial class Country : EntityBase<Country> {}
public class City
{
public string Name { get; set; }
}
public partial class City : EntityBase<City> {}
I want to be able to do something like this;
Region region = DAL.GetRegion(4);
region.Include("Countries.Cities");
So far I have the following;
public class EntityBase<T> where T : class
{
public void Include(string path)
{
// various validation has been omitted for brevity
string[] paths = path.Split('.');
int pathLength = paths.Length;
PropertyInfo propertyInfo = type(T).GetProperty(paths[0]);
object propertyValue = propertyInfo.GetValue(this, null);
if (propertyValue != null)
{
Type interfaceType = propertyInfo.PropertyType;
Type entityType = interfaceType.GetGenericArguments()[0];
// I want to do something like....
var propertyCollection = (ICollection<entityType>)propertyValue;
foreach(object item in propertyCollection)
{
if (pathLength > 1)
{
// call Include method of item for nested path
}
}
}
}
}
Clearly, the "var list = ...>" line doesn't work but you hopefully get the gist, and the foreach will not work unless is the propertyCollection is enumerable.
So it's the last bit, i.e. how do I enumerate an ICollection property of a class when I do not know the type of T until runtime?
Thanks
You don’t need Reflection for this. In order to enumerate it, you only need an IEnumerable. ICollection<T> inherits IEnumerable, so all of your collections will be enumerables. Therefore,
var propertyCollection = (IEnumerable) propertyValue;
foreach (object item in propertyCollection)
// ...
will work.
Generics are normally used when the client can resolve the generic type at compile-time.
Leaving that aside, since all you need to do is enumerate the propertyCollection (viewing each element of the sequence simply as a System.Object) all you need to do is:
var propertyCollection = (IEnumerable)propertyValue;
foreach(object item in propertyCollection)
{
...
}
This is perfectly safe since ICollection<T> extends IEnumerable<T>, which in turn extends IEnumerable. What T actually ends up being at run-time is irrelevant since the loop only requires object.
The real question is: Is System.Object sufficient for your purposes inside the loop?

Categories