Implementing generic methods from an interface using another interface - c#

I'm attempting to create a common interface which will allow me n methods of interacting with a database. I want my business application to be able to instantiate any of the connection methodologies and be assured the interface is identical.
Here's a simplified version of what I'm trying now.
Database Interface where IElement is another interface which would define a table.
public interface IDatabase
{
void setItem( IElement task ); //this works fine
List<T> listTasks<T>() where T : IElement; // this doesn't
}
IElement interface:
public interface IElement
{
int id { get; set; }
}
Implementation of IElement:
public class TaskElement: IElement
{
public int id { get; set; }
public string name {get; set; }
}
Implementation of IDatabase:
public class SQLiteDb: IDatabase
{
public SqLiteDb( SQLiteConnection conn )
{
database = conn;
}
public void setItem( IElement task )
{
// works fine when passed a new TaskElement() which is an implementation of IElement.
database.Insert( task );
}
//it all goes off the rails here
public List<T> listItems<T>() where T : IElement
{
var returnList = new List<IElement>
foreach (var s in database.Table<TaskElement>())
{ returnList.Add(s); }
return returnList;
}
I've tried a lot of variations on this but each one gives me a new issue. Here, for instance, there are two errors.
1)
The type arguments for method 'SQLiteDb.listTasks<T>()' cannot be inferred from the usage. Try specifying the type arguments explicitly.
2)
Cannot implicitly convert type 'System.Collections.Generic.List<TaskElement>' to 'System.Collections.Generic.List<T>'
I've tried changing the method to use an explicit type but have had issues there. If I use IElement (my generic interface for all elements )I can't return a list of TaskElement objects (my implementation of IElement) as it doesn't match the return type (List<IElement>) and if I change the return type to List<TaskElement> I'm not longer implementing the interface.
It's worth noting that I can easily get this to work if I stop using the interface and generics, but this seems like an ideal situation to use an interface. Maybe I'm trying to hard to cram a lot of stuff into an interface when another application (like direct inheritance) might be better?
Question
How can I implement an interface with a generic return value while limiting the types which can be returned to only implementations of another interface.

Let's look closely at your implementation of listItems:
public List<T> listItems<T>() where T : IElement
{
var returnList = new List<IElement>
foreach (var s in database.Table<TaskElement>())
{ returnList.Add(s); }
return returnList;
}
What you've done here is written a method where the caller is allowed to ask for any type they want in the list as long as that type implements IElement. But the code in your method doesn't give them a list of the type they want, it gives them a list of IElement. So it's violating the contract.
But the real root of your problem is database.Table<TaskElement>(). That can only ever give you instances of TaskElement. You need to make that T, but to do that you need an additional generic constraint:
public List<T> listItems<T>() where T : IElement, new
{
var returnList = new List<T>
foreach (var s in database.Table<T>())
{
returnList.Add(s);
}
return returnList;
}
This is because database.Table<T> has a new constraint, which means that it can only be given types that have a zero-parameter constructor (because that method is going to create instances of the given class).

I belive it should be something like this
public List<T> listItems<T>() where T : IElement
{
var returnList = new List<T>
foreach (var s in database.Table<T>())
{ returnList.Add(s); }
return returnList;
}

I think you are on the right track with explicitly defining your list like this:
public interface IDatabase
{
void setItem( IElement task ); //this works fine
List<IElement> listTasks<IElement>();
}
Since you can't directly cast List <TaskElement> to List <IElement> you will have to do a conversion in your listTasks method. There are several methods recommended here: Shorter syntax for casting from a List<X> to a List<Y>?. I think the Linq method is the simplest if you are ok with using Linq:
List<IElement> listOfIElement = listOfTaskElement.Cast<IElement>().ToList()

You need to use the Generic type when creating the object instance:
Instead of
var returnList = new List<IElement>();
Do this
var returnList = new List<T>();

Related

How to set a base member generic List<T> using derived specific List<TUser>

I have a compiler error when trying to set a generic base collection class member in this derived class.
error CS0029: Cannot implicitly convert type 'System.Collections.Generic.List<IntSegment>' to 'System.Collections.Generic.List<T>'
Here's the outline of my generic collection
public class Path<T> : IEnumerable<T> where T : Segment
{
private List<T> segments = new List<T>();
public List<T> Segments
{
set { segments = value; }
get { return this.segments; }
}
public Path()
{
this.Segments = new List<T>();
}
public Path(List<T> s)
{
this.Segments = s;
}
}
A derived generic class of this collection is then defined for a derived class IntSegment of Segment (for which the base collection is defined)
public class IntersectionClosedPath<T> : Path<T>, IEnumerable<T> where T : IntSegment
{
public IntersectionClosedPath(List<IntSegment> inEdges)
: base()
{
Segments = inEdges;
}
}
I can't understand why this assignment is not allowed. (I don't need to make a deep copy of the incoming List).
Change List<IntSegment> inEdges to List<T> inEdges and it will work. The problem is that Segments is known as a List<T>, where T : IntSegment, while inEdges is a List<IntSegment>. (For reasons I'll not go into here unless you ask, such an assignment is not allowed. Look up variance/covariance/contravariance if you're interested.)
A classic problem. A List<Derived> cannot be implicitly converted to a List<Base>.
You can cast the items in a List<Derived> and create a List<Base> like this:
listOfBase = listOfDerived.Cast<Base>().ToList();
A List<T> is not equivalent to a List<TBase> where T : TBase.
Why? Because List<T> doesn't inherit from List<TBase>, only the generic type parameters are related.
You can instead do this in the constructor:
Segments = inEdges.Cast<Segment>().ToList()
I would also change the constructor parameter to IEnumerable<IntSegment>
Equally, it might be that #Tim S. has the best solution based on what you want to achieve. Personally I believe he's probably nailed it.

Covariance not working with generic dictionary entry

Given the class below:
public class ConcreteEmployeeRoleCreator<T, TConcrete, TSpec>
where TConcrete : class, T, new()
where T : EmployeeRole
where TSpec : EmployeeRoleSpecification
{
public ConcreteEmployeeRoleCreator(TSpec spec) { Specification = spec; }
public TSpec Specification { get; private set; }
public T Create() { return new TConcrete(); }
}
I would like to have a dictionary of 'creators', but I haven't been able to work out how to do it yet. If I try and define the dictionary using the lowest common denominator types, the compiler is not allowing an instance to be added
[Test]
public void Creator_CanCreateFromSpec() {
var creators = new Dictionary<string, ConcreteEmployeeRoleCreator<EmployeeRole, EmployeeRole, EmployeeRoleSpecification>>();
var spec = new SalesmanRoleSpecification();
var creator = new ConcreteEmployeeRoleCreator<EmployeeRole, Salesman, SalesmanRoleSpecification>(spec);
creators.Add("salesman", creator); <==== ** compile error **
}
Salesman is an EmployeeRole, and SalesmanRoleSpecification is an EmployeeRoleSpecification (or I wouldn't be able to define the creator above without a compiler error as well).
SO I guess it is the way I am declaring the dictionary? What am I doing wrong?
Cheers,
Berryl
Generic covariance has to be specified at the declaration of the covariant type - and it can only be specified for interfaces and delegates.
So, given that you're using a class, a
ConcreteEmployeeRoleCreator<EmployeeRole, Salesman, SalesmanRoleSpecification>
will never be a
ConcreteEmployeeRoleCreator<EmployeeRole, EmployeeRole, EmployeeRoleSpecification>
You'll need to look for an alternative approach. To be honest, by the time you get to three type parameters and want two of them to be covariant, you've got a pretty hard-to-understand design to start with, I'm afraid :(

Typed<>/untyped design

I have an (existing) typed class of items:
Items<T>
T Value { get; }
T can be double, string or int.
I then have a class that has to hold several instances of Items. Within a single instance of this class, T is always the same. As it stands, the type actually contained is determined by a property and the container is not typed:
Data
DataType { get; set; }
Items<double>
double Value;
Items<string>
// ... and so on. Nasty stuff.
Ideally, of course, this would be
Data<T>
Items<T>
T value
Data instances are created from scratch in code, and can be loaded from a database. So of course a factory would be in our future, but what is the return type of the Create method?
Even worse, I need this:
DataCollection
// HERE'S THE PAIN: What's the type here?
List of Data<> instances with differing types
foreach (? data in someDataCollection)
if (thetypeof data is double)
doSomething();
else
doSomethingElse();
Now, I can solve this, but I can't see a CLEAN way to solve this.
My first issue is the declaration of DataCollection. What is the type of the list? List<object>, so it can hold Data<double> and Data<string>?
There actually is a clean way to solve this; you can use a Dictionary with keys of the data type and values which are of type generic Func<> . You then pass the type to your create method, which then looks up the Func<> to use in the Dictionary based on the type, and invokes that Func<> to create or process your object.
Since I am working from pseudo code, basically it would look something like the below; you can play with it and modify it to get it to serve your needs, but this is the basic idea.
First, create a parent class for all data objects; note that this class has a lookup dictionary for functions to invoke on various types, and note that it is abstract:
public abstract class Data
{
// A Lookup dictionary for processing methods
// Note this the functions just return something of type object; specialize as needed
private static readonly IDictionary<Type, Func<object, Data>> _processFunctions = new Dictionary
<Type, Func<object, Data>>()
{
{typeof(int), d => { return doSomethingForInt( (Data<int>) d); }},
{typeof(string), d => { return doSomethingForString( (Data<string>) d); }},
{typeof(double), d => { return doSomethingForDouble( (Data<double>) d); }},
};
// A field indicating the subtype; this will be used for lo
private readonly Type TypeOfThis;
protected Data(Type genericType)
{
TypeOfThis = genericType;
}
public Data Process()
{
return _processFunctions[this.TypeOfThis](this);
}
}
Now subclass Data with a generic type that can be instantiated:
class Data<T> : Data
{
// Set the type on the parent class
public Data() : base(typeof(T))
{
}
// You can convert this to a collection, etc. as needed
public T Items { get; set; }
public static Data<T> CreateData<T>()
{
return new Data<T>();
}
}
You can then create a DataCollection class using the parent type. Note the ProcessData() method; all it does now is loop over the elements and call Process() on each one:
class DataCollection
{
public IList<Data> List = new List<Data>();
public void ProcessData()
{
foreach (var d in List)
{
d.Process();
}
}
}
...and you're all set! Now you can invoke your DataCollection with different types of Data:
DataCollection dc = new DataCollection();
dc.List.Add(new Data<int>());
dc.List.Add(new Data<string>());
dc.List.Add(new Data<double>());
dc.ProcessData();
I think every time you need to do if-conditions on runtime data type, it means there's something wrong with the data structures. But every time I encounter situation like this, I have a hard time to solve it.
What I would try to do here is to wrap your primitive types into some kind of Adapters with conversion methods (possibly even implicit) and make all of them implement a common interface, let's say IDoSomething. Then, you can define the doSomething behaviors in IntWrapper, DoubleWrapper etc. separately. Then your DataCollection should be of type List<IDoSomething> and the loop can just call data.DoSomething() method from the interface.
Having implicit conversion allows you to use the collection in the natural way like data.Add(3) - you'll still be able to add the items without wrapping the privitives

How am I able to create A List<T> containing an open generic Interface?

I have a List which must contain IInteract Objects. But IInteract is a generic interface which requires 2 type arguments.
My main idea is iterate through a list of Objects and "Interact" one with another if they didn't interact yet.
So i have this object
List<IObject> WorldObjects = new List<IObject>();
and this one:
private List<IInteract> = new List<IInteract>();
Except I can't compile the last line because IInteract requires 2 type arguments. But I don't know what the arguments are until I add them. I could add interactions between Objects of Type A and A... or Objects of Type B and C.
I want to create "Interaction" classes which do something with the "acting" object and the "target" object, but I want them to be independent from the objects... so I could add an Interaction between for instance... "SuperUltraClass" and... an "integer".
Am I using the wrong approach?
Assuming IInteract is defined as something like
interface IInteract<T1, T2>
and you are using it for a field of a class Foo:
class Foo
{
List<IInteract...> field;
}
Then if you want to defer the decision of what types to bind to the IInteract type arguements you need to parameterize the container class:
class Foo<T1, T2>
{
List<IInteract<T1, T2>> field;
}
The type arguments to IInteract here will be bound when you define a concrete instantiation of the container class, like: var x = new Foo<int, double>(). This will cause the IInteract field to be of type IInteract<int, double> for that particular instantiation of the Foo generic type.
I think an interface hierarchy might make things easier. The top-level could be a non-generic interface with just the methods that you need to invoke, absent any type information. The second level would be those that required some typing...of course, it may be enough to simply have the implementing class instead of the second level interface.
public interface IInteract
{
void Interact();
}
public interface IInteract<TActor,TTarget> : IInteract
{
TActor Actor { get; set; }
TTarget Target { get; set; }
}
Then you can create your list of IInteract objects and it can contain any of the strongly typed IInteract<TActor,TTarget> objects, though only those methods on the non-generic interface will be available. The important thing will be the concrete implementations -- that is what will determine what code gets executed anyway.
I think you should use an inversion of control container (I've used Castle Windsor in the past). Then you can do something like this:
void Interact<TA, TB>(TA objectA, TB objectB)
{
var interact = Container.Resolve<IInteract<TA, TB>>();
interact.Interact(objectA, objectB);
}
you can do this:
private List<IInteract<SomeType, SomeOtherType>> = new List<IInteract<SomeType, SomeOtherType>>();
But like you said you don't know what types you're adding. So here are a couple of options:
1: Use object (or even dynamic) types:
private List<IInteract<object, object>> ...
2: Use generics in your class:
class Foo<T1, T2> {
private List<IInteract<T1, T2>> ...
}
...
Foo<string, int> bar = new Foo<string, int>();
In the second example you are locked into adding only strings and ints (or whatever you create the Foo object to be) to your list. In the first example you can mix and match, but you would have to do runtime type checking to figure out what you're pulling out of the list.
I'm not sure I completely understand what you're trying to accomplish. What you need to do is create a concrete class which implements your interface, and then use that in your List<>. Like so:
public interface IInteract
{
Type A { get; set; }
Type B { get; set; }
}
public class Interact : IInteract
{
public Type A
{
get { return a; }
}
public Type B
{
get { return b; }
}
}
And then use your concrete class in your list:
private List<Interact> = new List<Interact>();
You might be better off using a dictionary, where the key is a tuple of the two types that you are interacting, and the values are Interact, so each Interact implementation would have to do some casting
private Dictionary<Tuple<Type, Type>, IInteract<Object, Object>> interactions = new Dictionary<Tuple<Type, Type>, IInteract<Object, Object>>();
It's a bit messy but then you can add to it:
IInteract<Object, Object> superClassIntInteraction = someInteractionClass;
interactions.Add(new Tuple<Type, Type>(typeof(SuperClass),typeof(int)), superClassIntInteraction);
I'm assuming that you want to be able to search the list/dictionary to be able to find a specific interaction later on, which is where the dictionary comes in handy

When should or shouldn't I be using generic type constraints?

I've got a base class:
public abstract class StuffBase
{
public abstract void DoSomething();
}
And two derived classes
public class Stuff1 : StuffBase
{
public void DoSomething()
{
Console.WriteLine("Stuff 1 did something cool!");
}
public Stuff1()
{
Console.WriteLine("New stuff 1 reporting for duty!");
}
}
public class Stuff2 : StuffBase
{
public void DoSomething()
{
Console.WriteLine("Stuff 2 did something cool!");
}
public Stuff1()
{
Console.WriteLine("New stuff 2 reporting for duty!");
}
}
Okay, now say I've got a list of items:
var items = new List<StuffBase>();
items.Add(new Stuff1());
items.Add(new Stuff2());
and I want them all to call their DoSomething() method. I could expect to just iterate the list and call their DoSomething() method, so let's say I've got a method to do that called AllDoSomething() that just iterates over the list and does the job:
public static void AllDoSomething(List<StuffBase> items)
{
items.ForEach(i => i.DoSomething());
}
What is the practical difference of the following method?
public static void AllDoSomething<T>(List<T> items) where T: StuffBase
{
items.ForEach(i => i.DoSomething());
}
Both methods appear in real terms, although being syntactically different, to be doing the same thing.
Are they just different ways of doing the same thing? I understand generics and type constraints but can't see why I would use one way over the other in this instance.
This is because as of yet, C# does not support Covariance.
More formally, in C# v2.0 if T is a
subtype of U, then T[] is a subtype of
U[], but G is not a subtype of G
(where G is any generic type). In
type-theory terminology, we describe
this behavior by saying that C# array
types are “covariant” and generic
types are “invariant”.
Reference: http://blogs.msdn.com/rmbyers/archive/2005/02/16/375079.aspx
If you have the following method :
public static void AllDoSomething(List<StuffBase> items)
{
items.ForEach(i => i.DoSomething());
}
var items = new List<Stuff2>();
x.AllDoSomething(items); //Does not compile
Where as if you use the generic type constraint, it will.
For more information about Covariance and Contravariance], check out Eric Lippert's series of posts.
Other posts worth reading :
http://www.pabich.eu/blog/archive/2008/02/12/c-generics---parameter-variance-its-constraints-and-how-it.aspx
http://blogs.msdn.com/rmbyers/archive/2006/06/01/613690.aspx
http://msdn.microsoft.com/en-us/library/ms228359(VS.80).aspx
http://www.csharp411.com/convert-between-generic-ienumerablet/
http://research.microsoft.com/apps/pubs/default.aspx?id=64042
Why can't List<parent> = List<child>?
Suppose you had a list:
List<Stuff1> l = // get from somewhere
Now try:
AllDoSomething(l);
With the generic version, it will be allowed. With the non-generic, it won't. That's the essential difference. A list of Stuff1 is not a list of StuffBase. But in the generic case, you don't require it to be exactly a list of StuffBase, so it's more flexible.
You could work around that by first copying your list of Stuff1 into a list of StuffBase, to make it compatible with the non-generic version. But then suppose you had a method:
List<T> TransformList<T>(List<T> input) where T : StuffBase
{
List<T> output = new List<T>();
foreach (T item in input)
{
// examine item and decide whether to discard it,
// make new items, whatever
}
return output;
}
Without generics, you could accept a list of StuffBase, but you would then have to return a list of StuffBase. The caller would have to use casts if they knew that the items were really of a derived type. So generics allow you to preserve the actual type of an argument and channel it through the method to the return type.
In the example you provided there is no difference but try the following:
List<Stuff1> items = new List<Stuff1>();
items.Add(new Stuff1());
AllDoSomething(items);
AllDoSomething<StuffBase>(items);
The first call works well but the second one does not compile because of generic covariance

Categories