Alex Rivera | Logout

C# generics: Simplify type signature

Asked 2013-04-18T15:12:22.523
16

If I have a generic Item class that looks like this:

abstract class Item<T>
{
}

And a Container of Items that looks like this:

class Container<TItem, T>
    where TItem : Item<T>
{
}

Since TItem depends on T, is it possible to simplify the type signature of Container so that it takes only one type parameter? What I really want is something this:

class Container<TItem>
    where TItem : Item   // this doesn't actually work, because Item takes a type parameter
{
}

So I can instantiate it as follows:

class StringItem : Item<string>
{
}

var good = new Container<StringItem>();
var bad = new Container<StringItem, string>();

The compiler should be able to deduce that T is string when TItem is StringItem, right? How do I make this happen?

Desired usage:

class MyItem : Item<string>
{
}

Container<MyItem> container = GetContainer();
MyItem item = container.GetItem(0);
item.MyMethod();
Edit
Report

1 Answer

2

This should do what you want I think. Obviously you're now doing Container<string> not Container<StringItem> but as you've not included usage examples I can't see it being a problem.

using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var myContainer = new Container<string>();

            myContainer.MyItems = new List<Item<string>>();
        }
    }

    public class Item<T> { }

    public class Container<T>
    {
        // Just some property on your container to show you can use Item<T>
        public List<Item<T>> MyItems { get; set; }
    }
}

How about this revised version:

using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var myContainer = new Container<StringItem>();

            myContainer.StronglyTypedItem = new StringItem();
        }
    }

    public class Item<T> { }

    public class StringItem : Item<string> { }

    // Probably a way to hide this, but can't figure it out now
    // (needs to be public because it's a base type)
    // Probably involves making a container (or 3rd class??)
    // wrap a private container, not inherit it
    public class PrivateContainer<TItem, T> where TItem : Item<T> { }

    // Public interface
    public class Container<T> : PrivateContainer<Item<T>, T>
    {
        // Just some property on your container to show you can use Item<T>
        public T StronglyTypedItem { get; set; }
    }
}
answered 2013-04-18T15:37:02.607

Your Answer