By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,825 Members | 1,255 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,825 IT Pros & Developers. It's quick & easy.

Generics Help

P: n/a
Hi All,

I'm fairly new to C# and Generics and I'm wondering if anyone has some
suggestions for me.

I'm trying to implement a simple DAO framework using generics to keep
my code as clean as I can, however I'm getting an error with what seems
to me to be correct code. The error I'm getting is:

Error 1 Cannot implicitly convert type 'Sample.PersonDao' to
'Sample.Dao<Sample.Model>' F:\Documents and Settings\Bryan\My
Documents\Visual Studio
2005\Projects\EventManager\EventManager\Sample.cs 22 24 EventManager

Below is a snippet of code that will reproduce compilation error I
receive.

namespace Sample
{
// Base class for all Model objects.
abstract class Model { }

// Base class for all Data Access Objects.
abstract class Dao<TModelwhere TModel : Model { }

// Person model.
class Person : Model { }

// Data Access Object for a Person model.
class PersonDao : Dao<Person{ }

// Factory that returns the DAO for a model.
class DaoFactory
{
public Dao<ModelGetDao(Model model)
{
if (model is Person)
{
// Compilation error on the next line.
return new PersonDao();
}

return null;

}
}
}

Am I doing something completely wrong here? Is there something I
should be doing? Is there an alternate approach that might work
better?

Thanks in advance,
Bryan Kyle

Aug 12 '06 #1
Share this Question
Share on Google+
11 Replies


P: n/a
Bryan Kyle wrote:
Hi All,

I'm fairly new to C# and Generics and I'm wondering if anyone has some
suggestions for me.

I'm trying to implement a simple DAO framework using generics to keep
my code as clean as I can, however I'm getting an error with what seems
to me to be correct code. The error I'm getting is:

Error 1 Cannot implicitly convert type 'Sample.PersonDao' to
'Sample.Dao<Sample.Model>' F:\Documents and Settings\Bryan\My
Documents\Visual Studio
2005\Projects\EventManager\EventManager\Sample.cs 22 24 EventManager

Below is a snippet of code that will reproduce compilation error I
receive.

namespace Sample
{
// Base class for all Model objects.
abstract class Model { }

// Base class for all Data Access Objects.
abstract class Dao<TModelwhere TModel : Model { }

// Person model.
class Person : Model { }

// Data Access Object for a Person model.
class PersonDao : Dao<Person{ }

// Factory that returns the DAO for a model.
class DaoFactory
{
public Dao<ModelGetDao(Model model)
{
if (model is Person)
{
// Compilation error on the next line.
return new PersonDao();
}

return null;

}
}
}

Am I doing something completely wrong here? Is there something I
should be doing? Is there an alternate approach that might work
better?

Thanks in advance,
Bryan Kyle
Hi Bryan,

Unfortunately, this version of C# does not support
contravariance/covariance, which is what you're trying to do.

For example, List<Ais not the same, and is not a subset of List<Beven if
A inherits from B.

--
Hope this helps,
Tom Spink

Google first, ask later.
Aug 12 '06 #2

P: n/a

"Tom Spink" <ts****@gmail.comwrote in message
news:OK**************@TK2MSFTNGP02.phx.gbl...
Bryan Kyle wrote:
>Hi All,

I'm fairly new to C# and Generics and I'm wondering if anyone has some
suggestions for me.

I'm trying to implement a simple DAO framework using generics to keep
my code as clean as I can, however I'm getting an error with what seems
to me to be correct code. The error I'm getting is:

Error 1 Cannot implicitly convert type 'Sample.PersonDao' to
'Sample.Dao<Sample.Model>' F:\Documents and Settings\Bryan\My
Documents\Visual Studio
2005\Projects\EventManager\EventManager\Sample. cs 22 24
EventManager

Below is a snippet of code that will reproduce compilation error I
receive.

namespace Sample
{
// Base class for all Model objects.
abstract class Model { }

// Base class for all Data Access Objects.
abstract class Dao<TModelwhere TModel : Model { }

// Person model.
class Person : Model { }

// Data Access Object for a Person model.
class PersonDao : Dao<Person{ }

// Factory that returns the DAO for a model.
class DaoFactory
{
public Dao<ModelGetDao(Model model)
{
if (model is Person)
{
// Compilation error on the next line.
return new PersonDao();
}

return null;

}
}
}

Am I doing something completely wrong here? Is there something I
should be doing? Is there an alternate approach that might work
better?

Thanks in advance,
Bryan Kyle

Hi Bryan,

Unfortunately, this version of C# does not support
contravariance/covariance, which is what you're trying to do.

For example, List<Ais not the same, and is not a subset of List<Beven
if
A inherits from B.
Actually this will work, it's just hard to convince the compiler that it
will work. In the sample below I made two small changes.

First I introduced a non-generic superclass Dao over Dao<TModel>. Without
this Dao<TModelis a family of completely unrelated types, each the root of
its own inheritence hierarchy.

Second I declared the method GetDao as a generic method, and introduced an
obfuscating (object) cast to supress the compiler warning and changed the
type comparison from "is" to "==" because "is" includes subclasses, and this
isn't what you want:
public static Dao<TModelGetDao<TModel>() where TModel : Model
{
if (typeof(TModel) == typeof(Person))
{
// Compilation error on the next line.
return (Dao<TModel>)(object)new PersonDao();
}
Complete sample:

namespace Sample
{
// Base class for all Model objects.
abstract class Model { }
// Base class for all Data Access Objects.
abstract class Dao { }

// Family of base classes.
abstract class Dao<TModel: Dao where TModel : Model
{

}

// Person model.
class Person : Model { }

// Data Access Object for a Person model.
class PersonDao : Dao<Person>
{
}

// Factory that returns the DAO for a model.
class DaoFactory
{
public static Dao<TModelGetDao<TModel>() where TModel : Model
{
if (typeof(TModel) == typeof(Person))
{
// Compilation error on the next line.
return (Dao<TModel>)(object)new PersonDao();
}

return null;

}
}
}
David
Aug 12 '06 #3

P: n/a
"Bryan Kyle" <br********@gmail.comwrote:
I'm trying to implement a simple DAO framework using generics to keep
my code as clean as I can, however I'm getting an error with what seems
to me to be correct code.
The thing you are running into is called generic covariance, which C#
doesn't support. Basically, a List<Pigeonis not a List<Animal>. Why?
Well, if it were true, you'd be able to do this:

List<Animalanimals = new List<Pigeon>(pigeons);
animals.Add(new Cat());

.... and that would really throw the cat amongst the pigeons, since it
would break type safety.

(The analogue in your example is that Dao<Personis not a Dao<Model>.)

The solution to your problem is somewhat complex, and I've gone into
detailed explanations of similar situations on this newsgroup in the
past - search for generics covariance, about 2-6 weeks ago, you should
find it.

-- Barry

--
http://barrkel.blogspot.com/
Aug 12 '06 #4

P: n/a
"David Browne" <davidbaxterbrowne no potted me**@hotmail.comwrote:
"Tom Spink" <ts****@gmail.comwrote in message
news:OK**************@TK2MSFTNGP02.phx.gbl...
Unfortunately, this version of C# does not support
contravariance/covariance, which is what you're trying to do.

For example, List<Ais not the same, and is not a subset of List<Beven
if
A inherits from B.

Actually this will work, it's just hard to convince the compiler that it
will work.
There are always workarounds for genuinely type-safe scenarios - but
your modifications don't amount to a contradiction, since your code
doesn't enable covariance :)

-- Barry

--
http://barrkel.blogspot.com/
Aug 12 '06 #5

P: n/a
Look for the "Liskov substitution principle"

I also saw a great explanation of this on www.dnrtv.com show number 0009,
where Venkat Subramaniam explained this in detail.

Cheers,
Rick

"Bryan Kyle" wrote:
Hi All,

I'm fairly new to C# and Generics and I'm wondering if anyone has some
suggestions for me.

I'm trying to implement a simple DAO framework using generics to keep
my code as clean as I can, however I'm getting an error with what seems
to me to be correct code. The error I'm getting is:

Error 1 Cannot implicitly convert type 'Sample.PersonDao' to
'Sample.Dao<Sample.Model>' F:\Documents and Settings\Bryan\My
Documents\Visual Studio
2005\Projects\EventManager\EventManager\Sample.cs 22 24 EventManager

Below is a snippet of code that will reproduce compilation error I
receive.

namespace Sample
{
// Base class for all Model objects.
abstract class Model { }

// Base class for all Data Access Objects.
abstract class Dao<TModelwhere TModel : Model { }

// Person model.
class Person : Model { }

// Data Access Object for a Person model.
class PersonDao : Dao<Person{ }

// Factory that returns the DAO for a model.
class DaoFactory
{
public Dao<ModelGetDao(Model model)
{
if (model is Person)
{
// Compilation error on the next line.
return new PersonDao();
}

return null;

}
}
}

Am I doing something completely wrong here? Is there something I
should be doing? Is there an alternate approach that might work
better?

Thanks in advance,
Bryan Kyle

Aug 13 '06 #6

P: n/a
Thanks David!

Your suggestions helped me quite a bit. I've taken your sample code
and added a driver for it to see how it works and it works great!

Below is the sample working code + driver in case anyone else runs
across a similar issue.

using System;

namespace Sample
{
// Base class for all Model objects.
abstract class Model { }

abstract class Dao { }

// Base class for all Data Access Objects.
abstract class Dao<TModel: Dao where TModel : Model
{
public abstract TModel Get();
}

// Person model.
class Person : Model { }

// Data Access Object for a Person model.
class PersonDao : Dao<Person>
{
public override Person Get()
{
return new Person();
}
}

// Thing model.
class Thing : Model { }

// Data Access Object for a Thing model.
class ThingDao : Dao<Thing>
{
public override Thing Get()
{
return new Thing();
}
}

// Factory that returns the DAO for a model.
class DaoFactory
{
public Dao<TModelGetDao<TModel>() where TModel : Model
{
Dao dao = null;
if (typeof(TModel) == typeof(Person))
{
dao = new PersonDao();
}
else if (typeof(TModel) == typeof(Thing))
{
dao = new ThingDao();
}
return (Dao<TModel>)dao;
}
}

static class Driver
{
static void Main()
{
DaoFactory factory = new DaoFactory();

Dao<PersonpersonDao = factory.GetDao<Person>();
Console.WriteLine("DAO is " + personDao);
Person p = personDao.Get();
Console.WriteLine("Model is " + p);
Dao<ThingthingDao = factory.GetDao<Thing>();
Console.WriteLine("DAO is " + thingDao);
Thing t = thingDao.Get();
Console.WriteLine("Model is " + t);

}

}
}
David Browne wrote:
"Tom Spink" <ts****@gmail.comwrote in message
news:OK**************@TK2MSFTNGP02.phx.gbl...
Bryan Kyle wrote:
Hi All,

I'm fairly new to C# and Generics and I'm wondering if anyone has some
suggestions for me.

I'm trying to implement a simple DAO framework using generics to keep
my code as clean as I can, however I'm getting an error with what seems
to me to be correct code. The error I'm getting is:

Error 1 Cannot implicitly convert type 'Sample.PersonDao' to
'Sample.Dao<Sample.Model>' F:\Documents and Settings\Bryan\My
Documents\Visual Studio
2005\Projects\EventManager\EventManager\Sample.cs 22 24
EventManager

Below is a snippet of code that will reproduce compilation error I
receive.

namespace Sample
{
// Base class for all Model objects.
abstract class Model { }

// Base class for all Data Access Objects.
abstract class Dao<TModelwhere TModel : Model { }

// Person model.
class Person : Model { }

// Data Access Object for a Person model.
class PersonDao : Dao<Person{ }

// Factory that returns the DAO for a model.
class DaoFactory
{
public Dao<ModelGetDao(Model model)
{
if (model is Person)
{
// Compilation error on the next line.
return new PersonDao();
}

return null;

}
}
}

Am I doing something completely wrong here? Is there something I
should be doing? Is there an alternate approach that might work
better?

Thanks in advance,
Bryan Kyle
Hi Bryan,

Unfortunately, this version of C# does not support
contravariance/covariance, which is what you're trying to do.

For example, List<Ais not the same, and is not a subset of List<Beven
if
A inherits from B.

Actually this will work, it's just hard to convince the compiler that it
will work. In the sample below I made two small changes.

First I introduced a non-generic superclass Dao over Dao<TModel>. Without
this Dao<TModelis a family of completely unrelated types, each the root of
its own inheritence hierarchy.

Second I declared the method GetDao as a generic method, and introduced an
obfuscating (object) cast to supress the compiler warning and changed the
type comparison from "is" to "==" because "is" includes subclasses, and this
isn't what you want:
public static Dao<TModelGetDao<TModel>() where TModel : Model
{
if (typeof(TModel) == typeof(Person))
{
// Compilation error on the next line.
return (Dao<TModel>)(object)new PersonDao();
}
Complete sample:

namespace Sample
{
// Base class for all Model objects.
abstract class Model { }
// Base class for all Data Access Objects.
abstract class Dao { }

// Family of base classes.
abstract class Dao<TModel: Dao where TModel : Model
{

}

// Person model.
class Person : Model { }

// Data Access Object for a Person model.
class PersonDao : Dao<Person>
{
}

// Factory that returns the DAO for a model.
class DaoFactory
{
public static Dao<TModelGetDao<TModel>() where TModel : Model
{
if (typeof(TModel) == typeof(Person))
{
// Compilation error on the next line.
return (Dao<TModel>)(object)new PersonDao();
}

return null;

}
}
}
David
Aug 13 '06 #7

P: n/a
David Browne wrote:
>
"Tom Spink" <ts****@gmail.comwrote in message
news:OK**************@TK2MSFTNGP02.phx.gbl...
>Bryan Kyle wrote:
>>Hi All,

I'm fairly new to C# and Generics and I'm wondering if anyone has some
suggestions for me.

I'm trying to implement a simple DAO framework using generics to keep
my code as clean as I can, however I'm getting an error with what seems
to me to be correct code. The error I'm getting is:

Error 1 Cannot implicitly convert type 'Sample.PersonDao' to
'Sample.Dao<Sample.Model>' F:\Documents and Settings\Bryan\My
Documents\Visual Studio
2005\Projects\EventManager\EventManager\Sample.c s 22 24
EventManager

Below is a snippet of code that will reproduce compilation error I
receive.

namespace Sample
{
// Base class for all Model objects.
abstract class Model { }

// Base class for all Data Access Objects.
abstract class Dao<TModelwhere TModel : Model { }

// Person model.
class Person : Model { }

// Data Access Object for a Person model.
class PersonDao : Dao<Person{ }

// Factory that returns the DAO for a model.
class DaoFactory
{
public Dao<ModelGetDao(Model model)
{
if (model is Person)
{
// Compilation error on the next line.
return new PersonDao();
}

return null;

}
}
}

Am I doing something completely wrong here? Is there something I
should be doing? Is there an alternate approach that might work
better?

Thanks in advance,
Bryan Kyle

Hi Bryan,

Unfortunately, this version of C# does not support
contravariance/covariance, which is what you're trying to do.

For example, List<Ais not the same, and is not a subset of List<Beven
if
A inherits from B.

Actually this will work, it's just hard to convince the compiler that it
will work. In the sample below I made two small changes.

First I introduced a non-generic superclass Dao over Dao<TModel>. Without
this Dao<TModelis a family of completely unrelated types, each the root
of its own inheritence hierarchy.

Second I declared the method GetDao as a generic method, and introduced an
obfuscating (object) cast to supress the compiler warning and changed the
type comparison from "is" to "==" because "is" includes subclasses, and
this isn't what you want:
public static Dao<TModelGetDao<TModel>() where TModel : Model
{
if (typeof(TModel) == typeof(Person))
{
// Compilation error on the next line.
return (Dao<TModel>)(object)new PersonDao();
}
Complete sample:

namespace Sample
{
// Base class for all Model objects.
abstract class Model { }
// Base class for all Data Access Objects.
abstract class Dao { }

// Family of base classes.
abstract class Dao<TModel: Dao where TModel : Model
{

}

// Person model.
class Person : Model { }

// Data Access Object for a Person model.
class PersonDao : Dao<Person>
{
}

// Factory that returns the DAO for a model.
class DaoFactory
{
public static Dao<TModelGetDao<TModel>() where TModel : Model
{
if (typeof(TModel) == typeof(Person))
{
// Compilation error on the next line.
return (Dao<TModel>)(object)new PersonDao();
}

return null;

}
}
}
David
Hi David,

That's not contravariance.

--
Hope this helps,
Tom Spink

Google first, ask later.
Aug 13 '06 #8

P: n/a
"Bryan Kyle" <br********@gmail.coma crit dans le message de news:
11**********************@i42g2000cwa.googlegroups. com...

| Below is the sample working code + driver in case anyone else runs
| across a similar issue.

I'm sorry, but I really have to ask why on earth you are doing the extra
step of inheriting from a generic class just to get classes that are
differently named ??

| // Data Access Object for a Person model.
| class PersonDao : Dao<Person>
| {
| public override Person Get()
| {
| return new Person();
| }
| }

This is totally unnecessary. What is wrong with just using Dao<Person or
Dao<Thing?

Then you don't even need your factory :

public class Dao<modelT>
{
private modelT model;

public Dao(modelT model)
{
this.model = model;
}

public modelT Model
{
get { return model; }
}
}

{
Person p = new Person();

Dao dao = new Dao<Person>(p);

Model model = dao.Get();

// or you could assign it straight itno a Person, if you could be sure of
the type...

if (dao is Dao<Person>)
Person person = (Person) dao.Model

...
}

Or am I missing something ?

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer
Aug 13 '06 #9

P: n/a

"Joanna Carter [TeamB]" <jo****@not.for.spamwrote in message
news:OA****************@TK2MSFTNGP05.phx.gbl...
"Bryan Kyle" <br********@gmail.coma crit dans le message de news:
11**********************@i42g2000cwa.googlegroups. com...

| Below is the sample working code + driver in case anyone else runs
| across a similar issue.

I'm sorry, but I really have to ask why on earth you are doing the extra
step of inheriting from a generic class just to get classes that are
differently named ??

| // Data Access Object for a Person model.
| class PersonDao : Dao<Person>
| {
| public override Person Get()
| {
| return new Person();
| }
| }

This is totally unnecessary. What is wrong with just using Dao<Person or
Dao<Thing?
Presumably because PersonDao has additional implementation logic particular
to Person. Typically this would be somethind like key access or lookup
methods. EG:

public Person Lookup(string FirstName, string LastName)

This obviously can't go in the definition of Dao<TModelsince it applies
only for a particular TModel type.

David
Aug 14 '06 #10

P: n/a

"Tom Spink" <ts****@gmail.comwrote in message
news:uW**************@TK2MSFTNGP02.phx.gbl...
David Browne wrote:
>>
"Tom Spink" <ts****@gmail.comwrote in message
news:OK**************@TK2MSFTNGP02.phx.gbl...
>>Bryan Kyle wrote:

Hi All,

I'm fairly new to C# and Generics and I'm wondering if anyone has some
suggestions for me.
....
>>
David

Hi David,

That's not contravariance.

No indeed. But contravariance/covariance of generic parameters wasn't the
goal, and it wasn't really the problem with the OP's code.

The problem was that the return type of the GetDao method was just wrong.

public Dao<ModelGetDao(Model model)

Even if it had compiled, it's broken since a Dao<Modelis pretty useless,
and would require a client-side downcast to be at all useful.

public Dao<TModelGetDao<TModel>() where TModel : Model

Avoids the problems by returning the type that the client actually wants to
use.

David
Aug 14 '06 #11

P: n/a
Joanna Carter [TeamB] wrote:
"Bryan Kyle" <br********@gmail.coma crit dans le message de news:
11**********************@i42g2000cwa.googlegroups. com...

| Below is the sample working code + driver in case anyone else runs
| across a similar issue.

I'm sorry, but I really have to ask why on earth you are doing the extra
step of inheriting from a generic class just to get classes that are
differently named ??
The reason I'm wanting to use generics for this is so that I can define
a parameterized interface for the ModelDAO objects. For example, each
ModelDAO needs to have a Get method that is passed a type of Model and
will return an instance of the same type.

e.g.

public class PersonDAO
{
public Person Get(Person person);
}

public class ThingDAO
{
public Thing Get(Thing thing);
}

Had I not used generics for this, then implementing these methods would
be either left up to a development policy, or written generically:

public class PersonDAO
{
public Model Get(Model model);
}

While there's nothing wrong with that approach, it doesn't seem as
clean and again it is left up to the developer and the runtime
environment to determine if a given Model can be persisted using a
given ModelDAO.
>
| // Data Access Object for a Person model.
| class PersonDao : Dao<Person>
| {
| public override Person Get()
| {
| return new Person();
| }
| }

This is totally unnecessary. What is wrong with just using Dao<Person or
Dao<Thing?

Then you don't even need your factory :

public class Dao<modelT>
{
private modelT model;

public Dao(modelT model)
{
this.model = model;
}

public modelT Model
{
get { return model; }
}
}

{
Person p = new Person();

Dao dao = new Dao<Person>(p);

Model model = dao.Get();

// or you could assign it straight itno a Person, if you could be sure of
the type...

if (dao is Dao<Person>)
Person person = (Person) dao.Model

...
}

Or am I missing something ?

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer
Aug 14 '06 #12

This discussion thread is closed

Replies have been disabled for this discussion.