"Cyclic reference" with generics

T

Todor Todorov

I need a factory that produces items, and the items need to know about their
factory. Something like:

class Factory
{
Item GetNewItem();
}
class Item
{
Factory GetFactory();
}

Now, I would like to add some generics to the catory:

class Factory<TItem>
where TItem:Item
{
TItem GetNewItem();
}
class Item
{
Factory GetFactory();
}


Unfortunately, the Factory GetFactory() method now requries a generic type
and things won't work. Any siggestion how to fix that?
 
W

Walter Wang [MSFT]

Hi Todor,

If the factory can be used to create various items, can you make the
GetNewItem generic instead of the whole class?

class Factory
{
TItem GetNewItem<TItem>() where TItem: Item, new()
{
return new TItem();
}
}

Otherwise you will have to make the Item.GetFactory() return an object,
then you have to cast it at runtime accordingly.



Sincerely,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
For MSDN subscribers whose posts are left unanswered, please check this
document: http://blogs.msdn.com/msdnts/pages/postingAlias.aspx

Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications. If you are using Outlook Express/Windows Mail, please make sure
you clear the check box "Tools/Options/Read: Get 300 headers at a time" to
see your reply promptly.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
T

Todor Todorov

Hi Walter,

This works for the simple example, but not if the Factory needed more
methods. My first example was simplified, but here is a more thorough
example:

class Factory
{
TItem GetNewItem();
TItem GetExistingItem();
}

both the methods on the factory class must return the same type - TItem. I
don't want to have to write the type each time I have to call a method on
the factory. In the real case, there are more than two methods.

Also, when I invoke the GetFactory() method on the Item, I want to get the
factory for that kind of items. Any idea how to do that?

-- Todor
 
T

Todor Todorov

Hi again Walter,

May be I should try to explain what I want to achieve. I am used to a
language called Smalltalk, where this would be done in somet like (this is
pseudocode):

class Factory
{
TItem = typeof(Item);

TItem GetNewItem();
TItem GetExistingItem();
}

class Item
{
TFactory = typeof(Factory);

TFactory GetFactory();
}

class CarFactory : Factory
{
TItem = typeof(Car);
}

class Car : Item
{
TFactory = typeof(CarFactory);
}

As you can see, the template type variables TItem and TFactory are private
to the class definition. The rest is done using inheritance. I would
expected that the following would work:

abstract class Factory
{
virtual Item GetNewItem();
virtual Item GetExistingItem();
}

class CarFactory : Factory
{
override Car GetNewItem();
override Car GetExistingItem();
}

As you can see, the CarFactory returns more specific items than the abstract
Factory. I would expect this to be legal, since Car is an Item, so
CarFactory implemetens the protocol of Factory. Howeverm this is illegal.

Any suggestions how to solve this?




"Walter Wang [MSFT]" said:
Hi Todor,

If the factory can be used to create various items, can you make the
GetNewItem generic instead of the whole class?

class Factory
{
TItem GetNewItem<TItem>() where TItem: Item, new()
{
return new TItem();
}
}

Otherwise you will have to make the Item.GetFactory() return an object,
then you have to cast it at runtime accordingly.



Sincerely,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
For MSDN subscribers whose posts are left unanswered, please check this
document: http://blogs.msdn.com/msdnts/pages/postingAlias.aspx

Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications. If you are using Outlook Express/Windows Mail, please make sure
you clear the check box "Tools/Options/Read: Get 300 headers at a time" to
see your reply promptly.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no
rights.
 
G

Guest

In your first simple example, it seems like you could just use the following
to solve your problem:

class Item
{
Factory<Item> GetFactory() { return new Factory<Item>(); }
}

But this may not work as well once you start adding a rich type hierarchy.
Generally you can use either of the two types of polymorphism (inheritance or
generics) to solve many problems, with inheritance involving more run-time
checks (down-casts) and generics being more strict at compile-time. There
are some limitations in how you can combine these two forms in C# (generic
type parameters are always "non-variant" in C#) - see here for details:
http://blogs.msdn.com/rmbyers/archive/2005/02/16/generic-type-parameter-variance-in-the-clr.aspx

Smalltalk is a very dynamic language, and so there are many checks going on
behind the scenes at run-time which have to be done explicitly in an explicit
staticly-typed language like C#. If you really want the smalltalk behavior,
you can write all your APIs to pass Objects, and have casts wherever you need
them. But of course, this isn't considered good style in a statically typed
language. Regardless, smalltalk-style type hierarchies will map much better
to inheritance in C#, than generics which imposes much stricter requirements
(in order to get the benefits of compile-time guarantees).

Rick
 
T

Todor Todorov

Hi Rick!

Thanks for the link to the blog entry. It explains a lot in a very clear
way. I see the limitations of the generic implementation in C# :-(

I only mentioned Smalltalk because I was thinking how my solution would have
been written in Smalltalk. Actually, it's a new project and I am trying to
do it the C# way. Unfortunately, I still find .Net immature to solve complex
real world scenarios. I will always trade away the type-safe nature of C#
for the freedom I can have in a 100% dynamic and polymorphic language, even
there may be a small performance penalty. But that's my humble opinion.

Can you elucidate me, why can't I override a method and return a more
specific implementation? Example:
class Base
{
virtual object DoSomething() { ... }
}
class Derived
override string DoSomething() { ... }
}


I read some of the other entries on your blog. Interesting stuff!

-- Todor
 
W

Walter Wang [MSFT]

Hi Todor,

Rick is currently out of office for several days, so his reply maybe a
little late.

Yes the covariance in return type is a highly demanded feature in C#:

#Feedback: Need covariant return types in C# / all .Net langage
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?Feedbac
kID=90909


Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
W

Walter Wang [MSFT]

Hi Todor,

Thanks very much for your great feedback on our products. I've forwarded
them to product team. They're indeed very valuable for us.

I'm about to close this post, before closing I want to double check that
you don't have any other questions or concerns. If you do, please feel free
to let me know by replying here or email me directly.

Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
T

Todor Todorov

I hoped you or Rick Byers could explain the reason why I can't override a
method and return a more
specific implementation? Example:
class Base
{
virtual object DoSomething() { ... }
}
class Derived
override string DoSomething() { ... }
}

Otherwise, close the post.

-- Todor
 
U

UL-Tomten

I hoped you or Rick Byers could explain the reason why I can't override a
method and return a more specific implementation?

I think Walter answered this in his post about covariance in return
types. The rationale for not allowing the return type to differ in
overridden functions is probably that it ensures there are no
surprises at runtime (imagine when the base constructor calls virtual
function which is overridden to return a derived type). I think
the .NET solution to this is currently generics, which I think would
suit your needs here (see Rick's response).
 
T

Todor Todorov

The rationale for not allowing the return type to differ in
overridden functions is probably that it ensures there are no
surprises at runtime (imagine when the base constructor calls virtual
function which is overridden to return a derived type).

Example?
 
U

UL-Tomten


Not in C#, no, since return type covariance doesn't exist. But instead
of returning a base type and casting it as a derived type, maybe you'd
want to return an interface? This can provide flat type safety if
you're types aren't based on inheritance. The dependency problem in
Generics can only be solved by making everything generic, which I
guess in your case might mean

class Factory<T>
{
Item<T> GetNewItem();
}
class Item<T> where T : ItemBase
{
Factory<T> GetFactory();
}
interface/class ItemBase { ... }

Wouldn't this be cyclic enough?
 
W

Walter Wang [MSFT]

Hi Todor,

Please check following blog:

#Cyrus' Blather : Covariant return types revisited
http://blogs.msdn.com/cyrusn/archive/2004/12/08/278661.aspx

<quote>
...in order for the runtime to do override resolution it needs to match the
signature of the method in both the base and derived classes to determine
which method is being overridden. However, they require that the return
types be the same in order to consider the signature a match.
</quote>

You may want to refer to the book <<Common Language Infrastructure
Annotated Standard>> to get more information.

The blog also proposed a workaround using Attribute to implement return
type covariance, though it does have some drawbacks.

Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
W

Walter Wang [MSFT]

Hi Todor,

I'm writing again to check the status of this post.

What do you think of my last reply? Do you think the workaround in the blog
I mentioned useful for you?

Please feel free to let us know if there's anything else we can help.
Thanks.


Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top