Casting generic collection to concrete implementation in C# 2.0 - c#

Chosen Solution
Thanks for the help everyone. I've decided to do the following.
public static class PersonCollection
{
public static List<string> GetNames(RecordCollection<Person> list)
{
List<string> nameList = new List<string>(list.Count);
foreach (Person p in list)
{
nameList.Add(p.Name);
}
return nameList;
}
}
I'm trying to cast a generic collection RecordCollection to a derived collection PersonCollection, but I get a cast exception:
RecordCollection<Person> col = this.GetRecords<Person>(this.cbPeople);
PersonCollection people = (PersonCollection)col;
The reason I'm trying to do this is two-fold:
The derived classes (eg, PersonCollection) can have instance methods (eg, GetLastNames) which shouldn't be in the base class.
The method GetRecords is generic so I can get a collection of any Record objects.
What is the best approach to solve this in C# 2.0? What is the most elegant approach to solving this?
This is signature of GetRecords:
public RecordCollection<T> GetRecords<T>(ComboBox cb) where T : Record, new()
This is my base implementation:
public abstract class Record : IComparable
{
public abstract int CompareTo(object other);
}
public class RecordCollection<T> : ICollection<T> where T : Record, new()
{
private readonly List<T> list;
public RecordCollection()
{
this.list = new List<T>();
}
// Remaining ICollection interface here
}
I have derived objects based on that base implementation as follows:
public class Person : Record
{
public Person()
{
// This is intentionally empty
}
public string Name
{
get;
set;
}
public override int CompareTo(object other)
{
Person real = other as Person;
return this.Name.CompareTo(real.Name);
}
}
public class PersonCollection : RecordCollection<Person>
{
}

Your approach does not work because cast does not convert instances of one class to instances of another class.
You did not give the code of GetRecords<> method, but presumably GetRecords returns RecordCollection, and not PersonCollection (it has new RecordCollection somewhere in the code, doesn't it?).
You cannot cast RecordCollection to PersonCollection unless this particular instance actually is PersonCollection. Presicely because it does not have these additional methods.
This is like
SomeClass obj=new SomeClass();
DerivedClass o=(DerivedClass)obj; //throws exception

Your best bet is to use some sort of factory call inside GetRecords, so that when you request a 'collection' of Person it will return PersonCollection as RecordCollection<Person>.
A naive implementation can use a few if's, else you can associate concrete collection type to record types via a Dictionary<Type,Type>.

One option:
Make the methods on the derived types non-extension static methods that take in a specialized RecordsCollection ie
public static List<string>GetLastNames( RecordsCollection<Person> people )
so you can have usage along the lines of
RecordCollection<Person> somePeople = GetRecords<Person>(cbPeople);
List<string> lastNames = PersonCollecion.GetLastNames( somePeople );
It's not as pretty as the extension methods, but not too bad either.
edit: Removed erroneous info previously posted and replaced with potential solution

Related

Downcasting baseclass into derived generic type C#

I am struggling with an issue related with conversion between generic, possibly it's an easy one.
Basically I want to create a list of base class and add into it multiple classes.
public interface IQueryEngineDependency
{
public IEnumerable<QueryDependencyDetail> GetDependencies<>();
}
public abstract class QueryDependencyDetail
{
public int Order { get; set; }
}
public class QueryDependencyDetail<TEntity, TKey> : QueryDependencyDetail
where TEntity : BaseEntity<TKey>
{
public virtual Func<TEntity, object> Key { get; set; }
public IQueryable<TEntity> Data { get; set; }
public Func<TEntity, object> JoinKey { get; set; }
public Expression<Func<TEntity, bool>> WhereClause { get; set; }
}
Problem
I have a class, per example, that implements the interface shown above but I am figuring it out the right way to implement this.
public class TestQueryDependency : IQueryEngineDependency
{
public IEnumerable<QueryDependencyDetail> GetDependencies()
{
var dependencies = new List<QueryDependencyDetail>
{
new QueryDependencyDetail<Tasks, long>
{
Order = 1,
Data = null // just to simplify
}
};
return dependencies;
}
}
If I call the method GetDependencies somewhere in the code how can I make the downcasting to access the generic type fields? I mean I will get the instances of QueryDependencyDetail type. Then is it possible to convert it to QueryDependencyDetail<TEntity, TKey>?
Or is there another way to do this?
EDIT
var testDep = new TestQueryDependency();
var dependencies = testDep.GetDependencies();
Remember that dependencies may have up to 20 different instances in my particular implementation.
How can I access the Data field, per example? (Just a simple scenario)
var first = dependencies.FirstOrDefault()?.Data; ?????
I will need this to perform dynamic queries using LINQ.
Thanks in advance.
I am not sure what you are trying to accomplish.
What if you put the generic arguments on the engine interface?
public interface IQueryEngineDependency<TEntity,TKey> where TEntity : BaseEntity<TKey> {
public IEnumerable<QueryDependencyDetail<TEntity,TKey>> GetDependencies();
}
Then you can create a test engine:
public class TestQueryDependency : IQueryEngineDependency<Tasks,long> {
public IEnumerable<QueryDependencyDetail<Tasks,long >> GetDependencies() {
var dependencies = new[] {
new QueryDependencyDetail<Tasks, long> {
Order = 1,
Data = null // just to simplify
}
};
return dependencies;
}
}
You should be able to just cast it, i.e. (QueryDependencyDetail<TEntity, TKey>) myObject
However, you must make sure that the type actually match the real object. Lets take a simplified example:
public class A { }
public class B<T> : A { }
public static B<T> Test<T>(A a) => (B<T>)a;
and
var a = new B<int>();
var b1 = Test<int>(a); // works since a is of type of B<int>
var b2 = Test<string>(a); // Will throw invalid cast exception since a is not of type B<string>
You can also test the type:
if(a is B<int> b)
The problem here is that you have to know the actual type of the object. You cannot just cast a to B<T> without somewhere declaring what T actually is.
The solution I have used for these kind of problems is to avoid anything that needs to know the generic type. Make sure the interface or base class contain all methods you ever need when interacting with the object. This can be a bit complicated when multiple classes are involved, but it is usually possible.
edit:
A third option could be to use reflection. This can allow you to inspect the actual types of the generic type parameters. It may allow for things like creating another object with the same generic type parameter. The downside is that using reflection can be quite cumbersome and may be error prone and slow.

C# - list of subclass Types

I'd like to have a List of Class Types (not a list of Class instances) where each member of the List is a Subclass of MyClass.
For example, i can do this:
List<System.Type> myList;
myList.Add(typeof(mySubClass));
but i'd like to restrict the list to only accept subclasses of MyClass.
This is distinct from questions like this.
Ideally i'd like to avoid linq, as it's currently unused in my project.
Servy is right in his comment, and Lee in his: it's much more preferable to compose than inherit. So this is a good option:
public class ListOfTypes<T>
{
private List<Type> _types = new List<Type>();
public void Add<U>() where U : T
{
_types.Add(typeof(U));
}
}
Usage:
var x = new ListOfTypes<SuperClass>();
x.Add<MySubClass>()
Note that you can make this class implement an interface like IReadOnlyList<Type> if you want to give other code read access to the contained Types without other code having to depend on this class.
But if you want to inherit anyway, you could create your own class that inherits from List, then add your own generic Add method like this:
public class ListOfTypes<T> : List<Type>
{
public void Add<U>() where U : T
{
Add(typeof(U));
}
}
Just be aware of what Lee said: with this second version you can still Add(typeof(Foo)).
You should derive a list class from List and override the Add method to perform the type checking that you need. I'm not aware of a way in .NET to do that automatically.
Something like this could work:
public class SubTypeList : List<System.Type>
{
public System.Type BaseType { get; set; }
public SubTypeList()
: this(typeof(System.Object))
{
}
public SubTypeList(System.Type baseType)
{
BaseType = BaseType;
}
public new void Add(System.Type item)
{
if (item.IsSubclassOf(BaseType) == true)
{
base.Add(item);
}
else
{
// handle error condition where it's not a subtype... perhaps throw an exception if
}
}
}
You would need to update the other methods that add/update items to the list (index setter, AddRange, Insert, etc)

Use methods of instance of class stored in dictionary at runtime c#

Hello i have a problem in my code where i have to create an instance of class at run time. the classes inherits from a generic interface and this type of classes are stored in dictionary. then at runtime, use the methods of this new instanced class.
Heres my code:
Classes
public interface ILetters<T> where T : Item
{
Item SearchItem(T item);
}
Item is an Absract Class, ItemA, ItemB, ItemC inherits from it.
Child Classes Inherits from ILetters, lets just say they implemented SearchItem() differntly
public class ClassA : ILetters<ItemTypeA>
public class ClassB : ILetters<ItemTypeB>
public class ClassC : ILetters<ItemTypeC>
Main:
Dictionary<string, Type> dictTypeSelected = new Dictionary<string, Type>()
{
{"A", typeof(ClassA)},
{"B", typeof(ClassB},
{"C", typeof(ClassC)},
};
// Gets a string from user input
string type = combobox.SelectedItem.ToString();
var selectedType = Activator.CreateInstance(dictTypeSelected[type]);
selectedType.SearchItem() // <---- doesn't work.
is there a different approach or way i can fix this? thanks in advance
Although there are several solutions, I think, the main problem is generic interface.
At first look, there's no need for it here.
I'd suggest you to rebuild types hierarchy:
abstract class Item { }
interface ILetters
{
Item SearchItem(Item item);
}
abstract class Letters<T> : ILetters
where T : Item
{
public Item SearchItem(Item item)
{
return SearchItemOverride((T)item);
}
protected abstract Item SearchItemOverride(T item);
}
class ItemA : Item { }
class ClassA : Letters<ItemA>
{
protected override Item SearchItemOverride(ItemA item)
{
// ...
}
}
Then you can easily do this:
var selectedType = (ILetters)Activator.CreateInstance(dictTypeSelected[type]);
selectedType.SearchItem(...);
I think the major problem here is the var. Using var will cast your instance to an object.
You can try different alternatives here.
You can box the instance into a dynamic object and simply call the method with the risk to have a runtime exception
You can cast the instance to the concrete type but in this case I think you are not aware of it
You can call the method using reflection
In concrete:
1) dynamic selectedType = Activator.CreateInstance(...)
selectedType.SearchItem(...)
2) ClassA selectedType = Activator.CreateInstance(...)
selectedType.SearchItem(...)
3) object selectedType = Activator.CreateInstance(...)
MethodInfo searchMethod = selectedType.GetMethod("SearchItem")
searchMethod.Invoke(...)

Implement copy/deepcopy on multiple base classes

not sure if this maybe is a codeReview post but here we go:
My goal is to re-implement the way objects are copied within our application. We have multiple base classes:
CoreList<T> // for all list classes
BasicReference // for all reference classes
CoreObject // for all "normal" domain objects
All classes inherit from these base classes. Right now the copy method is implemented on the CoreObject class and will go through the object tree via reflection, looking at each property type and select the correct way to copy the type and finally returning always CoreObject.
There are some problems which I don't like about that approach, which is why I would like to change it:
After copying an domain object you always have to cast it "back" to the original type, for example: Animal = animal.Copy() as Animal;
All logic to copy each type is within the CoreObject class even though it should not know about other base classes.
So my first attempt was to introduce a interface:
public interface IObjectCopy<out T>
{
T Copy();
}
Which then should be implemented on all base classes. Then every class is responsible for the way it is copied. For example (pseudo code):
public class CoreObject : IObjectCopy<CoreObject>
{
public virtual GerCoreObject Copy()
{
foreach (var prop in properties)
{
if (prop.IsNoSimpleType)
{
(prop as IObjectCopy).Copy()
}
}
}
That solves the copy-responsibility problem, in addition inherited classes can take care of the copy logic themselves.
Unfortunately that does not solve the return type, I still have to cast it to the correct type. I did not think of a better solution to solve this. Any ideas?
This problem could be solved in OO using covariant return types. Unfortunately C# does not support covariant return types like Java and C++, requiring it to always break type safety.
Without breaking type safety (casting) in C# this is unfortunately not possible.
Here are two possible options:
//explicit interface implementation
public class Animal : CoreObject, IObjectCopy<Animal>
{
Animal IObjectCopy<Animal>.Copy()
{
return (Animal) base.Copy();
}
}
//does not require an explicit cast
IObjectCopy<Animal> animalCopy = myAnimal;
Animal copiedAnimal = animalCopy.Copy();
//second option: shadow the original method and cast inside the object
public class Animal : CoreObject, IObjectCopy<Animal>
{
public new Animal Copy()
{
return (Animal) base.Copy();
}
}
Animal copy = myAnimal.Copy();
Another option using bounded quantification:
public class CoreObject : IObjectCopy<CoreObject>
{
public CoreObject Copy()
{
return Copy<CoreObject>();
}
protected T Copy<T>()
where T : CoreObject, new()
{
T t = new T();
//implement copy logic:
return t;
}
}
public class Animal : CoreObject, IObjectCopy<Animal>
{
public new Animal Copy()
{
return Copy<Animal>();
}
}
If I understood it correctly, you need Curiously recurring template pattern
public class BaseClass<T> where T : BaseClass<T>
{
public virtual T Clone()
{
// Perform cloning with reflection.
return clone as T;
}
}
Then you just define your class as:
public class EndObject : BaseClass<EndObject>
{
}
EndObject e;
e.Clone() // Will return EndObject type

Keeping differently typed generic objects in one collection

I've been building a small access rules module for a project where every particular rule is reflected by a generic Rule<TEntity> object. The rule takes a delegate to execute a certain logic.
There is a RulesContext class that provides methods to check access to a certain entity "foo" like this:
rulesContext.CanIRead<Foo>(myFoo);
My intention was to store all rules build during a setup process into one collection. But every approach I tried lead to a dead end.
I thought of something like:
IDictionary<Type, Rule<object>> _rules = new Dictionary<Type, Rule<object>>();
and:
var fooRule = new Rule<Foo>(foo => foo.FullfillsACertainFooCriterion())
_rules.Add(typeof(Foo), fooRule);
The CanIRead implementation would make sure to use the dictionary properly:
public bool CanIRead<TEntity>(TEntity entity)
{
var rule = _rules[typeof(entity)];
return rule.CanIRead(entity);
}
But the compiler does not like this: Rule<Foo> cannot be assigned to a parameter of type Rule<object>. Which kind of makes sense since it would break the contract (which says that I can use the dictionary's methods with any object as parameter which does not hold true for the fooRule which only accepts Foo typed objects. - Liskov principle)
However I cannot think of a way to solve this. How could I store Rule objects with different types in one collection?
Can you do this:
[TestFixture]
public class ContraVariance
{
[Test]
public void TestNameTest()
{
var rules = new List<IRule<object>>(); //object is used just for demo here, probably some interface of yours is better
rules.Add(new Rule<A>());
rules.Add(new Rule<B>());
}
}
public class A { }
public class B { }
public class Rule<TEntity> : IRule<TEntity>
{
}
public interface IRule<out T>
{
}
If not I think you have to have a non-generic IRule or RuleBase (class)
The out keyword int the interface means that T is out only (Covariant) you can read about it here.
I guess that out will be a problem in your case, i suspect that the rules have methods with TEntity passed as arguments.
Instead of using IDictionary<Type, object> which could hold anything (e.g. DateTime) as a value in the dictionary, you could make the values strictly Rule objects
Here
namespace RuleConsole
{
class Program
{
static void Main(string[] args)
{
var context = new RulesContext();
var objA = new A();
var objB = new B();
context.AddRule<A>(new Rule<A>(objA));
context.AddRule<B>(new Rule<B>(objB));
Console.WriteLine(context.CanIRead<A>(objA));
Console.WriteLine(context.CanIRead<B>(objB));
Console.ReadKey();
}
}
public interface IRule { }
public interface IRule<T> : IRule { }
public class Rule<T> : IRule<T>
{
T _entity;
public Rule(T entity)
{
_entity = entity;
}
}
public class A { }
public class B { }
public class RulesContext
{
Dictionary<Type, IRule> _ruleDict= new Dictionary<Type, IRule>();
public void AddRule<TEntity>(Rule<TEntity> rule)
{
_ruleDict.Add(typeof(TEntity), rule);
}
public bool CanIRead<TEntity>(TEntity entity)
{
var rule = (IRule<TEntity>)_ruleDict[typeof(TEntity)];
//CanIRead implementation here
return rule != null;
}
}
}
That's inherently non-type-safe.
What do you want to happen if you write
_rules[typeof(Foor)].CanRead(new Bar());
You need to make a non-generic base class or interface to store in the dictionary.
Well, this is almost embarassing - but I think you've just helped me unblock my brain :-)
If the problem is that IDictionary<Type, Rule<object>> is too specific, IDictionary<Type, object> does the trick:
var fooRule = new Rule<Foo>(foo => foo.FullfillsACertainFooCriterion())
_rules.Add(typeof(Foo), fooRule);
(same as in the question, but compiles this time)
public bool CanIRead<TEntity>(TEntity entity)
{
var rule = (Rule<TEntity>)_rules[typeof(entity)];
return rule.CanIRead(entity);
}
The blocker in my brain was that I was thinking the more generic the type argument within Rule<...> was, the more objects should be allowed in the dictionary, but in this case it is the other way around: The more generic that argument is, the more specific the contract gets.
Take:
IDictionary<Rule<Foo>>
by replacing Rule by its base class object, the dictionary gets more generic. However, by replacing Foo by object, the whole thing actually gets more specialized!
The whole reason for that is that the type argument of Rule is used as an input parameter.
That's an important lesson...

Categories

Resources