I have the following construction of classes, here simplified as child classes of a 'mother' class called DataClass, which also contains one simple method:
public class DataClass
{
public int num { get; set; }
public string code { get; set; }
public PartClass part { get; set; }
public MemberClass member { get; set; }
public int Count()
{
Type t = typeof(DataClass);
return typeof(DataClass).GetProperties().Length;
}
}
public class PartClass
{
public int seriesNum { get; set; }
public string seriesCode { get; set; }
}
public class MemberClass
{
public int versionNum { get; set; }
public SideClass side { get; set; }
}
public class SideClass
{
public string firstDetail { get; set; }
public string secondDetail { get; set; }
public bool include { get; set; }
}
The issue is, I want to refactor the method so that it can give me an accurate counting of all properties found, including the ones in nested or child classes. In the above example, it only counts properties of DataClass, while I wanted it to return 2 for DataClass + 2 for PartClass + 1 for MemberClass + 3 for SideClass, sums up to 8 properties you may set through DataClass.
Can someone help me with this?
You can introduce interface with Count() method
public interface ICountable
{
int Count();
}
And use this interface to mark all types, which properties are participating in Count() calculation.
You can see the generic abstract class to implement this interface below. Generic T parameter is type whose properties need to be calculated. You implement a calculation logic only once and inherit this class where needed. You also go through all of properties, implementing ICountable, to calculate them as well (some kind of recursion)
public abstract class Countable<T> : ICountable
{
public int Count()
{
Type t = typeof(T);
var properties = t.GetProperties();
var countable = properties.Select(p => p.PropertyType).Where(p => typeof(ICountable).IsAssignableFrom(p));
var sum = countable.Sum(c => c.GetProperties().Length);
return properties.Length + sum;
}
}
and inherit it in your classes
public class DataClass : Countable<DataClass>
{
...
}
public class PartClass : Countable<PartClass>
{
...
}
public class MemberClass : Countable<MemberClass>
{
...
}
public class SideClass : Countable<SideClass>
{
...
}
And this is for the test
var dataClass = new DataClass();
var count = dataClass.Count();
It returns 8 as expected
Related
On one hand I have a list of capabilities, for example:
public interface ICapability
{
public string Name { get; }
}
public class RangeCapability<T> : ICapability
{
public string Name { get; set; }
public T Min { get; set; }
public T Max { get; set; }
}
public class SetCapability<T>
{
public string Name { get; set; }
public HashSet<T> Set { get; set; }
}
On the other hand I have a list of requirements
public interface IRequirement
{
public string Name { get; }
}
public class Requirement<T> : IRequirement
{
public string Name { get; set; }
public T Value { get; set; }
}
Both capability list may contain capabilities of different types T and requirement list may contain requirements of different types. The important thing is that if for a given name the underlying types match I should check if value is between min and max (for range class) or in a set like in the example below:
public class Entity
{
List<ICapability> Capabilities { get; set; }
public bool IsSatisfying(List<IRequirement> requirements)
{
foreach(var requirement in requirements)
{
var capability = Capabilities.FirstOrDefault(x => x.Name == requirement .Name);
//how to check if here if types match and if req. within range or in collection?
}
}
}
I am not sure how to match generic types of two different classes and then do the check suitable for the apropriate implementation (is within range/is present in set). Can somebody point me in the right direction how could I make it work?
I believe this is what you're looking for. Make the interfaces generic and also make the Entity class generic.
public interface INamed<T>
{
string Name { get; }
}
public interface ICapability<T> : INamed<T>
{
}
public class RangeCapability<T> : ICapability<T>
{
public string Name { get; set; }
public T Min { get; set; }
public T Max { get; set; }
}
public class SetCapability<T>
{
public string Name { get; set; }
public HashSet<T> Set { get; set; }
}
public interface IRequirement<T> : INamed<T>
{
}
public class Requirement<T> : IRequirement<T>
{
public string Name { get; set; }
public T Value { get; set; }
}
public class Entity<T>
{
List<ICapability<T>> Capabilities { get; set; }
public bool IsSatisfying(List<IRequirement<T>> requirements)
{
foreach (var requirement in requirements)
{
var capability = Capabilities.FirstOrDefault(x => x.Name == requirement.Name);
//how to check if here if types match and if req. within range or in collection?
if(capability is INamed<T>)
{
Console.WriteLine("types match");
}
}
}
}
I have a requirement to order several lists by the same value. But, for whatever reason, these lists contain objects of different types which share this value. Let's call it ChildID.
The simplified model code would look something like this:
public class Child
{
public string ChildID { get; set; }
}
public class Parent
{
public Child Child { get; set; }
}
public class OtherClassID
{
public int ID { get; set; }
public string ChildID { get; set; }
}
public class SomeOtherClass
{
public OtherClassID ID { get; set; }
}
So, in order to avoid code duplication, I tried this:
public interface IHasChildID
{
string GetChildID();
}
public class Child : IHasChildID
{
public string ChildID { get; set; }
public string GetChildID()
{
return ChildID;
}
}
public class Parent : IHasChildID
{
public Child Child { get; set; }
public string GetChildID()
{
return Child.ChildID;
}
}
public class OtherClassID
{
public int ID { get; set; }
public string ChildID { get; set; }
}
public class SomeOtherClass : IHasChildID
{
public OtherClassID ID { get; set; }
public string GetChildID()
{
return ID.ChildID;
}
}
And when I created a helper class with a helper method which takes an interface as a parameter, I expected it to work:
public static class ChildOrderHelper
{
public static IEnumerable<IHasChildID> OrderChildren(IEnumerable<IHasChildID> children)
{
var childrenList = children.ToList();
//do some splitting, ordering and conatenation of lists
return orderedList;
}
}
But, on every helper call I get an error:
List<Child> originalList = GetChildren(); // whatever
// some lines of code
var orderedList = ChildOrderHelper.OrderChildren(originalList).ToList(); // error
Error CS1503 Argument 1: cannot convert from
'System.Collections.Generic.List<NamespaceOne.Child>' to
'System.Collections.Generic.List<NamespaceTwo.IHasChildID>'
And so for every helper call, no matter the type.
One thing to note is that I've given an example with three distinct types that have this value and need to be ordered by it. In the project, there is probably 10 or more.
I guess there is something fundamental I don't yet understand about interface usage, but any help would be appreciated on this matter.
I'm not entirely sure what your overall use case is, but maybe it would be beneficial to make the OrderChildren method generic, as follows:
public static class ChildOrderHelper
{
public static IEnumerable<T> OrderChildren<T>(IEnumerable<T> children) where T : IHasChildID
{
var childrenList = children.ToList();
//just a simple example of what I'm guessing the method could do...
return childrenList.OrderBy(c => c.GetChildID()).ToList();
}
}
And call it as follows:
List<Child> originalList = GetChildren();
List<Child> orderedList = ChildOrderHelper.OrderChildren<Child>(originalList).ToList();
The approach can be taken like defining an interface and then implemenint that one in all the required classes or a base class that can lookup the child id.
Below is a sample of the source code.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections;
public class Program
{
public static void Main()
{
var parents = new List<Parent>();
parents.Add(new Parent{ChildId = "123"});
parents.Add(new Parent{ChildId = "321"});
parents.Add(new Parent{ChildId = "456"});
var result = ChildHelpers.OrderChildren(parents);
foreach(var res in result) {
Console.WriteLine(res.ChildId);
}
Console.WriteLine("Hello World");
}
}
public interface IChild {
string ChildId {get;set;}
}
public class Child : IChild {
public string Name {get;set;}
public string ChildId {get;set;}
}
public class Parent : IChild {
public Parent() {
child = new Child();
}
public Child child {get;set;}
public string ChildId {
get{
return child.ChildId;
}
set{
child.ChildId = value;
}
}
}
public class AnotherChild : IChild {
public string Description{get;set;}
public string ChildId {get;set;}
}
public static class ChildHelpers {
public static IEnumerable<IChild> OrderChildren(IEnumerable<IChild> children)
{
return children.OrderBy(c=>c.ChildId).AsEnumerable();
}
}
If you would like to playaround with this sample and see other options if required, please refer this link.
I'm struggling with a small problem: I need a TreeDataScructure. So what I mean is: I have a base class which holds a list of (lets call it RootObject). And all of these RootObjects have RootObjects children which can have children by themselves etc.. And to all of the RootObject you can add different types of components.
I tried it like this:
Base class:
RootObject[] Roots;
RootObject class:
RootObject Parent;
RootObject[] Childs;
IGenericComponent[] Components;
The problem is: when I for example need to get all components in the Base class I get a stackoverflow because looping through each Root and their children takes a long time. The second problem is serializing. It would be hard to serialize it because some components use um-managed memory. My second approach was to make a list of Roots and Components in the base class and then just give an index as Parent and children, which one can access is from the list. But that got very confusing soon.
Does anybody know a good, fast and easy way to a TreeStructure like that?
PS: Here is all my code to achieve this:
//These structs are like indexes to the list in the base class
public struct ScoAutoStride : IAutoStride<Sco>
{
public int Index { get; internal set; }
public bool IsValid { get => KerboEngine.Scenery.SceneryObjects.Contains(KerboEngine.Scenery.SceneryObjects[Index]); }
public Sco Get()
{
return KerboEngine.Scenery.SceneryObjects[Index];
}
public void Set(Sco newValue)
{
KerboEngine.Scenery.SceneryObjects[Index] = newValue;
}
}
public struct CompAutoStride : IAutoStride<ScoComponent>
{
public int Index { get; internal set; }
public bool IsValid { get => KerboEngine.Scenery.SceneryObjectComponents.Contains(KerboEngine.Scenery.SceneryObjectComponents[Index]); }
public ScoComponent Get()
{
return KerboEngine.Scenery.SceneryObjectComponents[Index];
}
public ScoComponent<T> CorrectGet<T>() where T : class
{
return (ScoComponent<T>)Get();
}
public void Set(ScoComponent newValue)
{
KerboEngine.Scenery.SceneryObjectComponents[Index] = newValue;
}
}
//Components:
public abstract class ScoComponent
{
public Type ChildType { get; internal set; }
public string Name { get; set; }
public bool Enabled { get; set; } = true;
public ScoComponent() { }
}
public class ScoComponent<T> : ScoComponent where T : class
{
public T RawClass { get; set; }
protected void InitThis(T value)
{
RawClass = value;
ChildType = value.GetType();
Name = ChildType.Name;
}
public ScoComponent() : base() { }
}
//Root object:
public class Sco
{
public string Name { get; set; } = "NULL";
public ScoAutoStride Parent { get; internal set; }
public List<ScoAutoStride> Childs { get; internal set; }
public List<CompAutoStride> Components { get; internal set; }
public object Tag { get; set; }
public bool Enabled { get; set; } = true;
public bool Popped { get; set; } = false;
public const int MaxChilds = int.MaxValue;
public g_Vec3 Position { get; set; }
public g_Quatr Rotation { get; set; }
public g_Vec3 Scale { get; set; }
}
The base class:
public class Scenery
{
public string Name { get; internal set; }
public List<Sco> SceneryObjects { get; internal set; }
public List<ScoComponent> SceneryObjectComponents { get; internal set; }
public int ScoStride { get; private set; } = 0;
public int CompStride { get; private set; } = 0;
public Scenery() { }
}
If you're only dealing with around 10000 items, then your tree shouldn't be very deep (a perfectly balanced binary tree of this size is 14 levels deep, for example) and so you should absolutely not be getting stack overflow errors unless:
your tree is really a list (eg. totally unbalanced, with every node having a single child, 10000 levels deep)
your tree is really a directed cyclic graph (where an object can appear as a descendent of itself, so traversal will never terminate)
your tree traversal algorithm is broken.
You've said that (2) can't happen, and (1) would probably be obvious to you, so the problem seems to lie in your tree traversal code that you haven't shared with us.
How do I make a generic SearchDTO which can be used as a template for any Search?
It should have any filter and other general information like TotalRecords, Sort Order, Pages, Start Row, etc
public abstract class SearchDTO
{
public object Id { get; set; }
public IList<T> SearchResults { get; set; }
public int PageSize { get; set; }
public int StartRowNo
{
get
{
return (CurrentPage - 1) * PageSize;
}
}
public int CurrentPage { get; set; }
}
And any Search Object looks like.
public class EmployeeSearchDTO:SearchDTO
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
But I get the following error in IList<T> property:
The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?).
How could I specify like returing a List of any objects and I can create other property like
public long TotalRecords
{
get
{
return SearchResults.Count;
}
set;
}
Is there any best approach other than this to solve this?
You need to specify T as type parameter on your class:
public abstract class SearchDTO<T>
Then when you will inherit from it - you should either provide concrete type instead of type parameter:
public class EmployeeSearchDTO : SearchDTO<MyConcreteType>
or successor class should be generic as well:
public class EmployeeSearchDTO<T> : SearchDTO<T>
You need the declaration on the class as well, to know what type T is:
Code for abstract class
public abstract class SearchDTO<T>
{
public object Id { get; set; }
public abstract IList<T> SearchResults { get; set; }
public int PageSize { get; set; }
public int StartRowNo
{
get
{
return (CurrentPage - 1) * PageSize;
}
}
public int CurrentPage { get; set; }
}
IList<T> SearchResults must be declare as abstract and override in inherited class.
Code of EmployeeSearchDTOP
public class EmployeeSearchDTO:SearchDTO<Employee>
{
public override IList<Employee> SearchResults { get; set; }
}
Create Employee class and move FirstName & LastName properties in Employee class.
Employee Class
public class Employee
{
public string FirstName {get; set; }
public string LastName {get;set;}
}
Until and unless there is a specific reason for you to use a abstract class what you want can be achieved by simply using a template class:
public class SearchDTO<T>
{
public object Id { get; set; }
public IList<T> SearchResults { get; set; }
public int PageSize { get; set; }
public int StartRowNo
{
get
{
return (CurrentPage - 1) * PageSize;
}
}
public int CurrentPage { get; set; }
}
For creating object all you need to do is this:
SearchDTO<EmployeeSearchDTO> obj=new SearchDTO<EmployeeSearchDTO>();
And instead of having SearchResults property create a function that would return a list of EmployeeSearchDTO objects, like this:
public IList<T> SearchResults()
{
IList<T> listObj=new List<T>();
//your code here
return listObj;
}
I have the following interface declarations:
interface IOrder<T> where T: IOrderItem
{
IList<T> Items { get; set; }
}
interface IOrderItem
{
IOrder<IOrderItem> Parent { get; set; } // What do I put here?
}
I want the items in the list to have a reference to the header object, so it can use the ID and other fields from the header.
In my concrete classes, it complains that I don't implement "Parent" properly.
class StoreOrder : IOrder<StoreOrderItem>
{
public IList<StoreOrderItem> Items { get; set; }
}
class StoreOrderItem : IOrderItem
{
public StoreOrder Parent { get; set; } // This doesn't satisfy the interface
}
I tried setting up IOrderItem as IOrderItem<T> and passing in the Parent type, but that lead to circular reference since the Header class requries the Item class type... I got confused.
Any advice on how to implement this properly?
If you define your interfaces like so:
interface IOrder<T> where T : IOrderItem<T>
{
IList<T> Items { get; set; }
}
interface IOrderItem<T> where T : IOrderItem<T>
{
IOrder<T> Parent { get; set; }
}
You can then implement them like this to get the functionality that you expect:
class StoreOrder : IOrder<StoreOrderItem>
{
public IList<StoreOrderItem> Items { get; set; }
}
class StoreOrderItem: IOrderItem<StoreOrderItem>
{
public IOrder<StoreOrderItem> Parent { get; set; }
}
class StoreOrder : IOrder<StoreOrderItem>
{
public int Id { get; set; }
}
class StoreOrderItem : IOrderItem
{
public IOrder<IOrderItem> Parent { get; set; } // This doesn't satisfy the interface
}
You may not specialize - IOrder<IOrderItem> is more general than StoreOrder
Here's a solution for changing the interfaces:
interface IOrder<TOrder, TOrderItem>
where TOrderItem : IOrderItem<TOrder>
{
IList<TOrderItem> Items { get; set; }
}
interface IOrderItem<TOrder>
{
TOrder Parent { get; set; }
}
Making changes to StoreOrder and StoreOrderItem to support the interface changes AND adding a couple properties to each for a later test:
class StoreOrder: IOrder<StoreOrder, StoreOrderItem>
{
public DateTime Date { get; set; }
public IList<StoreOrderItem> Items { get; set; }
}
class StoreOrderItem : IOrderItem<StoreOrder>
{
public string ItemName { get; set; }
public decimal ItemPrice { get; set; }
public StoreOrder Parent { get; set; }
}
...and now creating StoreOrder and StoreOrderItem instances, and putting them through their paces:
void Main()
{
var so = new StoreOrder { Date = DateTime.Now };
var item = new StoreOrderItem {
Parent = so,
ItemName = "Hand soap",
ItemPrice = 2.50m };
so.Items = new [] { item };
Console.WriteLine(item.Parent.Date);
Console.WriteLine(so.Items.First().ItemName);
}
...when run, printed:
3/16/2012 10:43:55 AM
Hand soap
Another option is to scrap the above and take this solution and alter it by adding the Parent property with the desired type and using explicit interface implementation to avoid casting at the call-sites, making for a StoreOrderItem implementation something like this:
class StoreOrderItem : IOrderItem
{
public string ItemName { get; set; }
public decimal ItemPrice { get; set; }
public StoreOrder Parent { get; set; } // note: original implementation
IOrder<IOrderItem> IOrderItem.Parent { // explicit interface implementation
get { return (IOrder<IOrderItem>)this.Parent; }
set { this.Parent = (StoreOrder)value; }
}
}
My favorite of the above is the first proposal above with the two-generic parameters to IOrder and the unconstrained generic-parameter on IOrderItem. A previous version I had posted and have now edited had both interfaces each with the same two generic types each with the same constraints. I felt like this was going a bit overboard so I pared it back to the above implementation. Although there is a complete lack of constraints on TOrder type parameter to IOrderItem - attempts to fudge other types in its place (e.g., object) resulted in compile errors. Using TOrder instead of just calling it T provides a hint about the expected type in the absence of the type constraint. That will be my final edit - I feel it is the most succinct of my attempts; if you are curious I can provide the former implementation that had the double-generic-constrained-types on the interfaces, but this is at least my preferred this solution. cheers!
Declaration to satisfy the interfaces:
class StoreOrder : IOrder<StoreOrderItem>
{
// interface members
public IList<StoreOrderItem> Items { get; set; }
// own members
public int Id { get; set; }
}
class StoreOrderItem : IOrderItem
{
public IOrder<IOrderItem> Parent { get; set; }
}
To access custom members you will have to cast:
class StoreOrderItem : IOrderItem
{
void Test()
{
int id = ((StoreOrder)this.Parent).ID;
}
}