I've got some class hierarchy - base class which is named "Group", which contains base information about single group, and class named "RootGroup" which inherits from "Group" and extend base class with some properties. List of groups is stored in the cache using base class: e.g. IEnumerable (some of them are ordinary groups, and some of them are root groups. The point is when the collection is being retrieved from the cache and cast back to IEnumerable type, specific information of RootGrop items are lost. Is there any way to prevent this situation except of remembering type of each cached item?
Jimmy
You can check each item as you retrieve it, and cast it to its proper type:
foreach (object item in list) {
if (item is RootGroup) {
Rootgroup rootGroup = item as RootGroup;
// do stuff with rootGroup
}
}
If you are using a generic collection, like a List<Group>, you can change the foreach like this:
foreach (Group item in list)...
If I understand your question correctly, your properties of RootGroup are not being "lost". The issue is you have a Group view of a RootGroup object. In order to access RootGroup properties, you must cast the object to a RootGroup.
A simple check:
if(groupItem is RootGroup)
{
RootGroup rootGroupItem = groupItem as RootGroup;
// Do stuff
}
Another way...
//from cache
IEnumerable<Group> groupsFromCache = GetGroupsFromCache();
IEnumerable<RootGroup> rootGroups = groupsFromCache.OfType<RootGroup>();
See http://www.thinqlinq.com/default/Using-Cast-Or-OfType-Methods.aspx
This has various niceties associated with deferred execution, but without more detail I can't really tell if that makes a difference. And like other posts noted, your information associated with the child class is not lost, you just need to put it in a form where its accessible.
Related
I'm making ASP.NET MVC app and i have class Order but i want to have 2 additional properties in it just for view. I figured out i will just make a class ViewOrder which derives from Order and has 2 additional properties so i could just assign Order object to OrderView and then set those 2 properties and pass this object to view.
Is it the proper way? When i was looking for answer on casting people were giving examples like "Cat inherits from mammal. You can't cast mammal to cat because it could be a dog" or something like that.
List:
var orderList = new List<Order>(_context.Orders)
Like that it doesn't even compile:
List<OrderView> orderViewList = (List<OrderView>)orderList;
This compile but throws "InvalidCastException":
var orderViewList = orderList.Cast<OrderView>().ToList();
Probably the simplest solution is to perform an explicit mapping operation:
List<Order> orderList = new List<Order>(_context.Orders);
List<OrderView> orderViewList = new List<OrderView>(); // Empty.
foreach (Order order in orderList)
{
OrderView orderView = new OrderView;
orderView.OrderNo = order.OrderNo;
orderView.CustomerId = order.CustomerId;
// ... etc
orderViewList.Add(orderView);
}
You cannot cast base class to derived class, there is no built-in method. You can either write a constructor OrderView(Order) that can do the conversion and use Linq to make it look clean.
// OrderView constructor
public OrderView(Order order)
{
this.OrderNo = order.OrderNo;
}
// Linq to create new list
List<OrderView> orderView = orders.Select(o => new OrderView(o));
Or use it this way, but not recommended
List<Order> orders = new List<OrderView>();
I must apologize for the previous answer. The problem lies here:
List<OrderView> orderViewList = (List<OrderView>)orderList; //<== Casting
The real truth is: Order is the parent of Orderview. So you cannot create a parent and assign it to a child. You can only create a child and assign it to a parent.
So, OrderView is another version of Order. But Order is not a version of OrderView.
Here's a thorough example:
when a child is assigned to a parent, any other features the parent doesn't have that the child has are ignored. But features that are required by a child, are required from a parent when that parent is assigned to a child. Which generates this casting issue.
I am not sure if what you're trying to do will serve you in the long run but there's probably a better approach of doing it. Please provide your Order class and identify what you specifically want to achieve with OrderView. Because the way I understand it, OrderView is supposed to be a method within Order provides a representation of Order you can simply create those extra fields you mentioned as private fields so that you can use them to create this OrderView() method.
So, I created a list:
protected Dictionary<Type, List<Entity>> entities;
The Entities shown above inherit multiple interfaces such as Clickable, Hoverable and Focusable.
My question is iterating over them, I need a method that allows quick rendering of the entire list i.e:
foreach (KeyValuePair<Type, List<Entity>> entry in entities)
{
foreach (Entity e in entry.Value)
{
e.Render(delta, drawingContext);
}
}
and also allows for iterating over the individual inherited types:
foreach (Clickable c in entities[typeof(Clickable)])
{
... Perform click
}
For my question:
does "typeof" include the types that are inherting clickable? e.g:
abstract class ClickableEntity : Entity, Clickable
My issue is efficiency and expandability, I understand that I could just use multiple lists but this approach allows me to understand the inner-workings of c#.
Is it efficient? Big-O maybe?
does "typeof" include the types that are inherting clickable?
No, it doesn't. ClickableEntity and Clickable are two different types, so they are different keys in the dictionary.
Instead of a dictionary, you could just use a single List<Entity>, and filter it using OfType:
protected List<Entity> entities;
foreach (var c in entities.OfType<Clickable>())
{
... Perform click
}
I am a fan of Jeff Bay's Object Calisthenics exercise:
http://www.xpteam.com/jeff/writings/objectcalisthenics.rtf
and I have had good results implementing first class collections by creating objects to encapsulate both the implementation of the collection and also the iteration over collections of objects.
This means instead of a List I have a EmployeeList object.
Typically when I create these objects, I don't implement any collection interfaces so external users cannot enumerate the inner collection, as I thought this was the whole point. However, one colleague was suggesting the opposite - implement ICollect interface to make it more flexible.
This refactoring site seems to be in the same direction, although it doesn't completely remove access to the inner collection: http://sourcemaking.com/refactoring/encapsulate-collection
// Foreach method
foreach (var employee in employees)
{
if (employee.IsManager)
{
managers.Add(employee);
}
}
// Linq method
managers = employees.Where(e => e.IsManager);
// Encapsulated iteration method
managers = employees.GetAllManagers();
public IEnumerable<Employee> GetAllManagers() // Inside Employees class
{
return employees.Where(e => e.IsManager);
}
Am I right in saying the last method is favourable? When would you ever want to expose your inner collection by implementing IEnumerable for example?
IEnumerable would probably be a good choice. You could have a private list of your Employee object, and expose it publicly as an IEnumerable to let people use it in loops, LINQ, etc.
Since IEnumerable doesn't allow you to modify the collection being iterated over, you don't have to worry about the consumer of your EmployeeList changing the internals.
Providing an iteration method wouldn't be as ideal, since it breaks POLA, and requires some effort on the programmer consuming the API to find the method he wants to call. Thinking about it, you'd never have code like the following in .NET.
var list = new List<T>;
foreach (var item in list.GetAllItems())
{
// Whut?
}
I have several models that includes nested classes and lists. Many of the class members have attributes that I also have to read in.
I'm looking for a dynamic way (possibly through Linq or Reflection) to retrieve the values and attributes of all generic objects within the specified model.
Any suggestions are welcome.
Edit:
Using the ObjectManager as per x0r's suggestion, I can see all of the data. The remaining part of this issue requires member annotation. Is there some way to copy over the PropertyInfo of each class member?
ObjectWalker objectWalker = new ObjectWalker(objectToValidate);
foreach (Object o in objectWalker)
{
if (isGeneric(o.GetType()))
{
PropertyInfo property = o.GetType().GetProperty(o); // <-- This does not work... Need to obtain annotations somehow
object[] Attributes = property.GetCustomAttributes(typeof(Attribute), true);
foreach (Attribute attribute in Attributes)
{
// Annotations processing goes here
}
}
}
Have a look at the ObjectWalker
It helps you to parse an object graph and visit all unique elements.
As you can see it stores only a stack of objects and Current returns an Object.
You could modify this so the Walker would save a class that contains all the data you need for each property (Like a propertyinfo object or a list of attributes).
I would like to search the bodies of all outlook items. I know how to do this for the four PIM items (Notes/Tasks/Appointments/Contacts). But the code is identical for all of them with the exception of casting the COM object to the specific item type (i.e., ContactItem, AppointmentItem, etc). Is there a parent class for these PIM items, so that I can do something like this in my loop:
using Outlook = Microsoft.Office.Interop.Outlook
List SearchFolderItems( Outlook.Folder folder )
{
List results = new List();
foreach( object folderItem in folder.Items )
{
//GenericPIMItem is what I am wishing for
Outlook.GenericPIMItem item = (Outlook.GenericPIMItem)folderItem;
if( item.Body.ToLower().Contains( "secret sauce" ) )
{
results.Add( item.Name );
}
}
}
Body is a common property of the four PIM items I want to get at. Is there such a parent item? Seems poor API design if not? I suppose I could abstract the folder item, to make it look like there is a parent item... I also tried to do this using reflection, but couldn't quite get there.
Any suggestsion?
Looking at the documentation, I don't see a class like you want.
For Outlook 2007, the list of objects that can be in an Items collection is here. It includes things like distribution lists that don't have a body, which makes what you want unlikely.
While the PIM items might be derived from a common class, it is not creatable through the com object, but, all items also return a class property, which is an enumeration for what type of item it is. You could check this property for the four types of items you want before you cast,