I have implemented my own collection class for various reasons.
How to avoid casting failure on ItemCollection resultCollection = (ItemCollection)list;? I'm inheriting from List<T> so shouldn't I be able to cast? Can I modify my BaseEntityCollection to become able to do this?
static class Program
{
static void Main()
{
ItemCollection collection = new ItemCollection();
Item item = new Item();
item.ID = 1;
item.Name = "John";
collection.Add(item);
List<Item> list = collection.FindAll(x => x.ID == 1 && x.Name == "John");
ItemCollection resultCollection = (ItemCollection)list; // It's breaking here
}
}
public class ItemCollection : BaseEntityCollection<Item>
{
}
public class Item : BaseEntity
{
public int ID { get; set; }
public string Name { get; set; }
}
public abstract class BaseEntityCollection<T> : List<T>, IEnumerable<T> where T : BaseEntity, new()
{
}
public abstract class BaseEntity
{
}
I know that I can implement FindAllseparately on my ItemCollection But I wanted to take advantage of all the methods available on List<T>.
Also I know that I can do list.ForEach(resultCollection.Add);. But that means iterating the collection all over again which I'd like to avoid.
Just change your constructors around so that you can initialize it with a List<Item> collection. This lets you initialize the item collection with another collection:
static class Program
{
static void Main()
{
ItemCollection collection = new ItemCollection();
Item item = new Item();
item.ID = 1;
item.Name = "John";
collection.Add(item);
List<Item> list = collection.FindAll(x => x.ID == 1 && x.Name == "John");
ItemCollection resultCollection = new ItemCollection(list);
}
}
public class ItemCollection : BaseEntityCollection<Item>
{
//Allow default constructor
public ItemCollection() { }
//Construct with a list collection
public ItemCollection(IEnumerable<Item> collection)
: base(collection)
{
}
}
public class Item : BaseEntity
{
public int ID { get; set; }
public string Name { get; set; }
}
public abstract class BaseEntityCollection<T> : List<T>, IEnumerable<T> where T : BaseEntity, new()
{
//Still be able to create blank items
public BaseEntityCollection() { }
public BaseEntityCollection(IEnumerable<T> collection)
: base(collection)
{
}
}
public abstract class BaseEntity
{
}
In order to avoid iterating your list twice, I would change the following:
List<Item> list = collection.FindAll(x => x.ID == 1 && x.Name == "John");
to
var list = collection.Where(x => x.ID == 1 && x.Name == "John");
Which will lazy-load your list (in a sorts), but it will only iterate your collection once, when you create the new ItemCollection from it.
To augment the already great answers. You asked:
I'm inheriting from List so shouldn't I be able to cast?
Yes and no.
Your particular cast works at compile time but not at runtime.
Casting is a way of telling the compiler, "Trust me. This will work at runtime."
At runtime, we can cast from a Base class to a Descendant class only when the underlying object inside of Base is actually an object of type Descendant.
For instance, keeping in mind that string descends from object, here is an illustration of why your cast fails at runtime.
// builds but fails at runtime
object o1 = new object();
string s1 = (string)o1;
// builds and works at runtime
// because o2 is a string in object's clothing
object o2 = (object)"";
string s2 = (string)o2;
ItemCollection resultCollection = new ItemCollection();
resultCollection.AddRange(collection.Where(x => x.ID == 1 && x.Name == "John"));
If by chance you don't have the AddRange extension method, make it.
void AddRange<T>(this ItemCollection c, IEnumerable<T> items) => foreach(T i in items) c.Add(i);
Related
I have multiple data-points and an associated data-processor for each.
public interface IDataPointProcessor<T> where T : DataPointInputBase
{
DataPointOutputBase GetOutput(T input);
}
I load a list of data points from a file and wish to process them using its single associated processor.
foreach (DataPointInputBase item in input.DataPoints)
{
//assuming item coming in is of type 'X' how do I get correct processor
var type = typeof(IDataPointProcessor<X>);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p) && !p.IsAbstract);
IDataPointProcessor<X> matchedType = ??
}
How do I solve for 'X' so I can instantiate it and process the input?
Update #1
Combining answers from below from Slava and Lucky I get the following, but it throws an exception - 'Object does not match target type.' even though it all seems to match up ok in debugger. Is it possible to cast as IDataPointProcessor<> and call interface method cleanly, ie: instance.GetOutput(item);
foreach (DataPointInputBase item in input.DataPoints)
{
Type typeGenArg = item.GetType();
Type typeInterfaceGen = typeof(IDataPointProcessor<>).MakeGenericType(typeGenArg);
Type type = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(x => x.GetTypes())
.Where(x => typeInterfaceGen.IsAssignableFrom(x) && !x.IsAbstract)
.FirstOrDefault();
Type genericType = typeof(IDataPointProcessor<>);
Type dependedGenericType = genericType.MakeGenericType(typeof(DataPointInputBase));
var method = dependedGenericType.GetMethod("GetOutput");
var instance = Activator.CreateInstance(type);
//currently throws:System.Reflection.TargetException: 'Object does not match target type.'
var result = method.Invoke(instance, new object[] { item });
//Ideally I want to do this and avoid the magic strings etc
//var temp_output = instance.GetOutput(item);
}
Update #2
To keep things moving I've hard coded the type 'Age_Input' to validate the thing works. What am I missing to call the hard coded bit dynamically?
I should be able to cast instance to IDataPointProcessor<IDataPointInput> and call GetOutput() on the interface
foreach (IDataPointInput item in input.DataPoints)
{
Type typeGenArg = item.GetType();
Type typeInterfaceGen = typeof(IDataPointProcessor<>).MakeGenericType(typeGenArg);
Type type = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(x => x.GetTypes())
.Where(x => typeInterfaceGen.IsAssignableFrom(x) && !x.IsAbstract)
.FirstOrDefault();
Type genericType = typeof(IDataPointProcessor<>);
Type dependedGenericType = genericType.MakeGenericType(typeof(IDataPointInput));
var instance = Activator.CreateInstance(type);
if (instance is IDataPointProcessor<Age_Input>)//hard-coded
{
var processor = instance as IDataPointProcessor<Age_Input>;
Age_Input temp = item as Age_Input;
var result = processor.GetOutput(temp);
}
if (instance is DataPointProcessorBase<DataPointInputBase>)
{
//false
}
if (instance is IDataPointProcessor<DataPointInputBase>)
{
//false
}
if (instance is IDataPointProcessor<IDataPointInput>)
{
//false - shouldn't this work?
}
}
Age_Input is a trivial class, inheriting from a dumb base class and an empty interface
public class Age_Input : DataPointInputBase, IDataPointInput
{
public int AgeExact { get; set; }
}
public class DataPointInputBase : IDataPointInput
{
}
public interface IDataPointInput
{
}
Processor class is similarly simple
public abstract class DataPointProcessorBase<T> : IDataPointProcessor<T> where T : IDataPointInput, new()
{
//public abstract DataPointOutputBase GetOutput(DataPointInputBase input);
public abstract DataPointOutputBase GetOutput(T input);
}
public interface IDataPointInput
{
}
public interface IDataPointProcessor<IDataPointInput>
{
DataPointOutputBase GetOutput(IDataPointInput input);
}
Firstly, you should make covariant your interface like this.
public interface IDataPointProcessor<in T> where T : DataPointInputBase
{
DataPointOutputBase GetOutput(T input);
}
You should retrieve types which is implemented by IDataPointProcessor<>, then you should create the instance of retrieved type and invoke the method of generic type.
Type genericType = typeof(IDataPointProcessor<>);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => genericType.IsAssignableFrom(p) && !p.IsAbstract).ToList();
var dependedGenericType = genericType.MakeGenericType(typeof(DataPointInputBase));
var method = dependedGenericType.GetMethod("GetOutput");
var instance = Activator.CreateInstance(types[0]);
method.Invoke(instance, new object[] { new DataPointInputBase() });
So as is usually the case, if you can avoid Reflection you're generally better off. I traded a tiny bit of code smell for a much simpler solution.
Essentially I went back to basics and used dumb interfaces, and a helper method on the input that returned a primed instance of the corresponding processor.
Now my big reflection loop is replaced with this:
foreach (IDataPointInput item in input)
{
IDataPointProcessor processor = item.GetProcessor();
IDataPointOutput output = processor.GetOutput();
}
The code smell is this - not an issue
public override IDataPointProcessor GetProcessor()
{
return new Age_Processor(this);
}
Full code below
#region Interfaces
public interface IDataPointProcessor
{
IDataPointOutput GetOutput();
}
public interface IDataPointInput
{
IDataPointProcessor GetProcessor();
}
public interface IDataPointOutput
{
List<string> DebugStrings { get; set; }
}
#endregion
#region Base Classes
public abstract class DataPointProcessorBase : IDataPointProcessor
{
public abstract IDataPointOutput GetOutput();
}
public abstract class DataPointInputBase : IDataPointInput
{
public abstract IDataPointProcessor GetProcessor();
}
public abstract class DataPointOutputBase : IDataPointOutput
{
public List<string> DebugStrings { get; set; }
public DataPointOutputBase()
{
DebugStrings = new List<string>();
}
}
#endregion
public class Age_Output : DataPointOutputBase
{
}
public class Age_Input : DataPointInputBase
{
public int AgeExact { get; set; }
public override IDataPointProcessor GetProcessor()
{
return new Age_Processor(this);
}
}
public class Age_Processor : DataPointProcessorBase
{
public Age_Input Input { get; set; }
public Age_Processor(Age_Input input)
{
Input = input;
}
public override IDataPointOutput GetOutput()
{
Age_Output output = new Age_Output();
if (Input.AgeExact > 30)
{
output.DebugStrings.Add("Getting old");
}
else
{
output.DebugStrings.Add("Still young");
}
return output;
}
}
public class DecisionEngine
{
public void GetDecisions()
{
List<IDataPointInput> input = new List<IDataPointInput>();
input.Add(new Age_Input { AgeExact = 44 });
foreach (IDataPointInput item in input)
{
IDataPointProcessor processor = item.GetProcessor();
IDataPointOutput output = processor.GetOutput();
}
}
}
I'm having some trouble creating my own List structure. I'm trying to create a List structure called SortedList. The objective is for it to Sort its items as soon as add a new item. This list will not get too big in the project I'm using it for (maybe 50-100 items at most). However, I was testing by adding a simple item of class Employee which has a Name property. And I want this SortedList to sort on employee's Name.
Here is my attempt.
The Employee class
public class Employee : IComparer<Employee>
{
public string Name { get; set; }
public Employee()
{
}
public int Compare(Employee x, Employee y)
{
return string.Compare(x.Name, y.Name,true);
}
}
Here is the SortedList class that I'm trying to create.
public class SortedList<T> : IEnumerable<T>
{
private List<T> _list;
public List<T> List
{
get { return _list; }
set { _list = value; }
}
private Employee EmployeeComparer = new Employee();
public SortedList()
{
_list = new List<T>();
}
public void Insert(T item)
{
if (!_list.Contains(item))
{
_list.Add(item);
Sort(_list);
}
}
private void Sort(List<T> list)
{
var type = typeof(T);
switch (type.Name)
{
case "Int32":
case "String":
list.Sort();
break;
case "Employee":
Employee EmployeeComparer = new Employee();
list.Sort(EmployeeComparer);
break;
}
}
public IEnumerator<T> GetEnumerator()
{
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
From program.cs I'm basically populating the SortedList with three instances of Employee objects and I expect it to Sort it by employee's Name property and in the out put I expect to see this.
Barry
Neil
Zach
class Program
{
static void Main(string[] args)
{
SortedList<Employee> list = new SortedList<Employee>();
list.Insert(new Employee() { Name="Zach"});
list.Insert(new Employee() { Name = "Neil" });
list.Insert(new Employee() { Name = "Barry" });
foreach (var item in list)
{
Console.WriteLine(item.Name);
}
}
}
But I get a compiler error. It says:
Severity Code Description Project File Line Suppression State
Error CS1503 Argument 1: cannot convert from 'ExtensingLists.Employee' to 'System.Collections.Generic.IComparer<T>' ExtensingLists C:\E Drive\VSProjects\C-Sharp Generics Course\ExtensingLists\ExtensingLists\SortedList.cs 57 Active
The error says line 57, which is this:
list.Sort(EmployeeComparer);
What am I doing wrong? Please advise. Thank you.
The concrete question you're asking about is like asking why
int f(object o) { return o is int ? o : 0; }
fails to compile. Even if you've checked that o has type int at run-time, at compile-time it still has type object, which means it can't be used as the return value. You'd need a cast to get that working:
int f(object o) { return o is int ? (int)o : 0; }
and the same applies to your code.
But there's something more fundamentally wrong. Your Employee shouldn't be implementing IComparer<Employee>. It should be implementing IComparable<Employee>, which specifies not that an Employee object knows how to compare two other Employee objects, but that it knows how to compare itself to another Employee object. And when you do that, you should be able to just call list.Sort(); without checking the type at all.
The List.Sort method can be made to work in multiple ways.
This method uses the default comparer Comparer.Default for type T to determine the order of list elements. The Comparer.Default property checks whether type T implements the IComparable generic interface and uses that implementation, if available. If not, Comparer.Default checks whether type T implements the IComparable interface. If type T does not implement either interface, Comparer.Default throws an InvalidOperationException.
So by making the below change, it will start working for you
public class Employee : IComparable<Employee> {
public string Name { get; set; }
public Employee() {
}
public int CompareTo(Employee other) {
return string.Compare(Name, other.Name, true);
}
}
and the Below change in public class SortedList<T> : IEnumerable<T> {
private static void Sort(List<T> list) {
var type = typeof(T);
list.Sort();
}
This is not the only way to do, but a preferable way to do when the Types are intrinsically Orderable. You can also use the IComparer<T> interface, but that is used when the Type needs to be sorted in a way that IComparable<T> does not or when the Type is not an IComparable<T>. I have listed all the code here together
class Program {
static void Main() {
SortedList<Employee> list = new SortedList<Employee>();
list.Insert(new Employee() { Name = "Zach" });
list.Insert(new Employee() { Name = "Neil" });
list.Insert(new Employee() { Name = "Barry" });
foreach (var item in list) {
Console.WriteLine(item.Name);
}
}
}
public class Employee : IComparable<Employee> {
public string Name { get; set; }
public int Age { get; set; }
public Employee() {
}
public int CompareTo(Employee other) {
return string.Compare(Name, other.Name, true);
}
}
public class EmployeeAgeComparer : IComparer<Employee> {
public int Compare(Employee x, Employee y) {
return x.Age - y.Age;
}
}
public class SortedList<T> : IEnumerable<T> {
private List<T> _list;
public List<T> List {
get { return _list; }
set { _list = value; }
}
private EmployeeAgeComparer EmployeeComparer = new EmployeeAgeComparer();
public SortedList() {
_list = new List<T>();
}
public void Insert(T item) {
if (!_list.Contains(item)) {
_list.Add(item);
Sort(_list);
}
}
private void Sort(List<T> list) {
if (typeof(T) == typeof(Employee))
list.Sort((IComparer<T>)EmployeeComparer);
else
list.Sort();
}
public IEnumerator<T> GetEnumerator() {
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
now I use like this;
c1 = c1.AddItem(d1);
public static T AddItem<T, TItem>(this T entity, TItem item) where T : BaseClass<T>
{
//somecode
return entity;
}
but I want to be able to change value without return;
c1.AddItem(d1);
public static void AddItem<T, TItem>(this T entity, TItem item) where T : BaseClass<T>
{
//somecode
}
any idea how to make this work?
FULL CODE
public class C : BaseClass<C>
{
public virtual int CId { get; set; }
public virtual string Text { get; set; }
public virtual IList<D> DList { get; set; }
public C()
{
DList = new List<D>();
}
}
public static T AddItem<T, TItem>(this T entity, TItem item) where T : BaseClass<T>
{
var propertyList = item.GetType().GetProperties().ToList();
var prop = propertyList.Find(c => c.PropertyType == typeof(T));
if (propertyList.Any(c => c.PropertyType == typeof(T)))
{
propertyList.Find(c => c.PropertyType == typeof(T)).SetValue(item, entity);
}
else
{
((IList<T>)propertyList.Find(c => c.PropertyType == typeof(IList<T>)).GetValue(item)).Add(entity);
}
var a = ((IList<TItem>)entity.GetType().GetProperties().ToList().Find(c => c.PropertyType == typeof(IList<TItem>)).GetValue(entity));
if (a.GetType().Name == "PersistentGenericBag`1")
{
entity = entity.Load(x => (IList<TItem>)x.GetType().GetProperties().ToList().Find(c => c.PropertyType == typeof(IList<TItem>)).GetValue(x));
a = ((IList<TItem>)entity.GetType().GetProperties().ToList().Find(c => c.PropertyType == typeof(IList<TItem>)).GetValue(entity));
}
a.Add(item);
entity.Save();
return entity;
}
public static T Load<T, TItem>(this T entity, Func<T, IList<TItem>> listGetter) where T : class
{
using (var session = NHibernateHelper<T>.OpenSession())
{
T reAttached = session.Merge<T>(entity);
NHibernate.NHibernateUtil.Initialize(listGetter.Invoke(reAttached));
return reAttached;
}
}
Your problem appears to be caused by this line:
entity = entity.Load(x => (IList<TItem>)x.GetType().GetProperties().ToList().Find(c => c.PropertyType == typeof(IList<TItem>)).GetValue(x));
Now that you have posted the contents of the Load method, we can see that it, in turn, calls:
T reAttached = session.Merge<T>(entity);
// ...
return reAttached;
My knowledge of Hibernate is limited, but chances are good that, if not always, at least sometimes, the call to Merge will return a reference to a different object instance from what is passed in.
This has the cascading effect that, in your extension method, the local variable entity gets reassigned to a completely new object. Because the entity reference variable is a copy of the c1 reference variable (and not a reference to it), when it gets reassigned, the change is not reflected in the c1 variable. Your c1 variable effectively still points to the original entity instance before it got changed by the call to BaseClass.Load().
Basically, as others have already stated, to code an extension method that doesn't need to return an entity reference, you have to limit yourself to changing the state of the entity object through its methods/properties. You can't actually change the object reference completely, because this will never be reflected outside the method call.
In your case, it looks like you should stick with your original extension method that returns the entity reference.
Relevant reading: Parameter passing in C#
In particular, the section Sidenote: what is the difference between passing a value object by reference and a reference object by value? applies to what is happening here.
Strings are immutable, with other class-types your code should work.
public class BaseClass<TItem>
{
public BaseClass()
{
ItemList = new List<TItem>();
}
public List<TItem> ItemList { get; set; }
}
public static void AddItem<T, TItem>(this T entity, TItem item)
where T :BaseClass<TItem>
{
//somecode
entity.ItemList.Add(item);
}
public class TItem
{
public string Name { get; set; }
}
static void Main(string[] args)
{
BaseClass<TItem> myEntity = new BaseClass<TItem>();
TItem newItem = new TItem();
newItem.Name = "Hi";
myEntity.AddItem(newItem);
}
I have a custom list class let say,
public class Fruit
{
public string Name { get; set; }
public string Size { get; set; }
public string Weight{ get; set; }
}
Now I am adding records to it like this,
List<Fruit> Fruits= new List<Fruit>();
//some foreach loop
Fruit fruit = new Fruit();
fruit.Name = ...;
fruit.Size = ...;
fruit.Weight = ...;
Fruits.Add(fruit);
What I want ?
I want to make changes to Public Fruit Class in a way that it checks if any of fruit in custom list has already has same weight then just ignore it and continue e.g. don't add it to the list.
I would prefer doing it without changing foreach loop logic
Use LINQ .Any() - Determines whether any element of a sequence exists or satisfies a condition. (MSDN: http://msdn.microsoft.com/en-us/library/system.linq.enumerable.any.aspx)
if (!Fruits.Any(f => fruit.Weight != null && f.Weight == fruit.Weight))
Fruits.Add(fruit);
If duplicate weights are not allowed i would use a HashSet<Fruit> with a custom IEqualityComparer:
public class FruitWeightComparer : IEqualityComparer<Fruit>
{
public bool Equals(Fruit x, Fruit y)
{
if(x == null || y== null) return false;
if (Object.ReferenceEquals(x, y)) return true;
return x.Weight == y.Weight;
}
public int GetHashCode(Fruit obj)
{
return obj.Weight == null ? 0 : obj.Weight.GetHashCode();
}
}
Now you can use the HashSet constructor with this comparer:
HashSet<Fruit> Fruits = new HashSet<Fruit>(new FruitWeightComparer());
// ...
bool notInSet = Fruits.Add(fruit);
HashSet.Add returns true if the item could be added.
You can control it at insert time by simply not inserting already existing fruit
if (!myFruits.Any(f => f.Weight == newFruit.Weight))
myFruits.Add(newFruit);
If you can't manipulate the insertion logic you can make a custom list that wraps a normal List<T> and changes the behavior of Add like in the above example:
public class FruitsWithDistinctWeightList : IEnumerable<Fruit>
{
private List<Fruit> internalList;
... // Constructor etc.
public void Add(Fruit fruit)
{
if (!internalList.Any(f => f.Weight == fruit.Weight))
internalList.Add(fruit);
}
... // Further impl of IEnumerable<Fruit> or IList<Fruit>
}
You could also use some existing collection that does not allow duplicate items. For example some hash based collection such as HashSet<Fruit>:
var fruitsWithDistinctWeight = new HashSet<Fruit>(new FruitWeightComparer());
Where you'd use a comparer that says fruits with equal weight are equal:
public class FruitWeightComparer : IEqualityComparer<Fruit>
{
public bool Equals(Fruit one, Fruit two)
{
return one.Weight == two.Weight;
}
public int GetHashCode(Fruit item)
{
return one.Weight.GetHashCode();
}
}
Note that a HashSet<T> is not ordered like a list is. Note that all of the code above for simplicity assumes that the Weight field is set. If you have public setters on your class (i.e. no guarantees of this) you would have to change appropriately.
I have a base class Foo with a property for identify the primary key from a data base item.
Other classes descend from my base class Foo and contains another properties for particularities these classes. Each descended class represents a distinct table in the database.
Generally when these data are loaded these items are stored in the same list of type List<Foo>.
And when I need to use some item I find this based on the primary key.
My problem occurs when these items have the same primary key, and when look a item from a descended class FooB eventually find a class FooA because this is comes first, then the places that perform a cast to FooB raise a excpetion.
var list = new List<Foo>();
list.Add(new FooA() { PrimaryKey = 1 });
list.Add(nwe FooB() { PrimaryKey = 1 });
public Foo FindItem(int pk)
{
return list.First(it => it.PrimaryKey == 1);
}
In many places I use this method to find my item according to my needs.
var item = (FooB)FindItem(1);
In other classes:
var item = (FooA)FindItem(1);
In my case this code is used in many places in the system, changing the List<Foo> to lists of the descended item is a solution but this means making changes in many places because I can not pass the type of each item everywhere I use.
I need a solution that does not change the base list.
You will need to rewrite the FindItem(1) method to return not one instance of Foo but instead a special object that will contain both FooA instance with PrimaryKey==1 and the FooB instance with PrimaryKey==1.
The second step is to provide cast operators that will convert this special object to the type you need so that the code var item = (FooB)FindItem(1) will work as expected.
Below is fully working code that implements such a solution. The main drawback is that you have to provide the cast operator implementations for each derived type you are using. You might also be able to derive FooWrapper from Foo (would be very simple in this case with just a single property in Foo but it depends on your actual Foo class).
using System;
using System.Collections.Generic;
using System.Linq;
namespace FooWrapper
{
class Program
{
private static List<Foo> list = new List<Foo>();
static FooWrapper FindItem(int id)
{
return new FooWrapper(list.Where(o => o.PrimaryKey == id));
}
static void Main(string[] args)
{
list.Add(new FooA() { PrimaryKey = 1, Title = "aaa" });
list.Add(new FooB() { PrimaryKey = 1, Age = 123 });
// test the implicit cast to Foo type. this prefers the FooA type.
Foo item = FindItem(1);
Console.WriteLine(item.PrimaryKey + " - " + item.GetType().Name);
// retrieve the FooWrapper and cast it to FooA type.
var itema = (FooA)FindItem(1);
Console.WriteLine(itema.PrimaryKey + " - " + itema.Title + " - " + itema.GetType().Name);
// retrieve the FooWrapper and cast it to FooB type. The wrapper instance
// retrieved is the same, but the cast retrieves the correct type
var itemb = (FooB)FindItem(1);
Console.WriteLine(itemb.PrimaryKey + " - " + itemb.Age + " - " + itemb.GetType().Name);
}
}
public sealed class FooWrapper
{
private FooA _a;
private FooB _b;
public FooWrapper(IEnumerable<Foo> items)
{
FooA a;
FooB b;
foreach (var i in items)
{
a = i as FooA;
if (a != null)
{
this._a = a;
}
else
{
b = i as FooB;
if (b != null)
this._b = b;
}
}
}
public static implicit operator Foo(FooWrapper obj)
{
if (obj == null)
return null;
return obj._a == null ? (Foo)obj._b : obj._a;
}
public static explicit operator FooA(FooWrapper obj)
{
if (obj == null)
return null;
return obj._a;
}
public static explicit operator FooB(FooWrapper obj)
{
if (obj == null)
return null;
return obj._b;
}
}
public abstract class Foo
{
public int PrimaryKey { get; set; }
}
public class FooA : Foo
{
public string Title { get; set; }
}
public class FooB : Foo
{
public int Age { get; set; }
}
}
public T FindItem<T>(int pk) where T : Foo
{
return list.OfType<T>().First(it => it.PrimaryKey == 1);
}
Usage:
var item = FindItem<FooB>(1);
OfType<T> has two beneficial effects on list:
It filters the list items to those of type T and
it returns an IEnumerable<T>, so the return value of FindItem is already correctly typed and does not need to be cast.
Use generics in your FindItem function:
public T FindItem<T> (int pk) where T : Foo
{
return list.OfType<T>().SingleOrDefault(it => it.PrimaryKey == pk);
}