无法从类型推断嵌入式类型参数

时间:2018-02-01 14:08:11

标签: c# generics

我来自c ++角落,并且对c#generics有一些不确定的问题。

问题:

  • 为什么以下代码不起作用?
  • 您是否有一些链接可以帮助我提高我的通用知识?

解释

public abstract class Item{}
public abstract class ParentItem<T> : Item where T : Item{
    public ObservableCollection<T> Childs;
}
public class ItemC : Item {}
public class ItemB : ParentItem<ItemC> {}
public class ItemA : ParentItem<ItemB> {}


public void NewChildItem<P, C>(P parent) where P : ParentItem<C> where C : Item, new()
{
    C child = new C();
    parent.Childs.Add(child); //From class ParentItem
}

public class MyEventArgs : EventArgs
{
    public object Parent;
}

用法

public void NewItem(MyEventArgs e)
{
    datas.NewChildItem(e.Parent);          // That would be nice to avoid case analysis
    datas.NewChildItem(e.Parent as ItemA); // Error cant resolve paramter type

//Following variant works, but is obvious ugly
    if(e.Parent is ParentItem<ItemA>)
        datas.NewChildItem<ParentItem<ItemA>,ItemA>(e.Parent as ParentItem<ItemA>)
    else if(e.Parent is ParentItem<ItemB>)
        datas.NewChildItem<ParentItem<ItemB>,ItemB>(e.Parent as ParentItem<ItemB>)
}

解释

我在3层上有一个带有HierarchicalDataTemplate的TreeView。 我的数据结构:

ItemA
    -ItemB
    -ItemB
        -ItemC
ItemA
    -ItemB
        -ItemC

使用contextmenu我想添加一个孩子。我解雇MyEvent以获取父节点(如果是root则为null),它应该创建一个新的子节点。

如果我有设计错误,请告诉我。我想变得更好。

1 个答案:

答案 0 :(得分:0)

我认为你做错了。你想拥有带孩子的物品。您可以为通用项目生成子项:

    // Master-class with business-logic or so..
    public abstract class Item
    {
        private static int nextId = 0; // Some Id-generator
        public Item()
        {
            this.Id = nextId++;
        }

        public int Id { get; set; } // Id to see the difference between the objects.

        public string Name { get { return this.GetType().Name + ":" + this.Id; } } // For Console..
    }

    // Class with business-logic for items which can have children
    public abstract class ItemWithChildren<TChildClass> : Item where TChildClass : Item, new()
    {
        public ItemWithChildren()
        {
            this.Childs = new ObservableCollection<TChildClass>();
        }
        public ObservableCollection<TChildClass> Childs { get; set; }

        public Item NewChildItem()
        {
            TChildClass newItem = new TChildClass();
            Childs.Add(newItem);
            return newItem;
        }

        public List<Item> GetChildItemsTypeless()
        {
            return this.Childs.Select(s => (Item) s).ToList();
        }
    }

    // implementation of you concrete types..
    public class ItemA : ItemWithChildren<ItemB>, IItemWithChildren { }
    public class ItemB : ItemWithChildren<ItemC>, IItemWithChildren { }
    public class ItemC : Item { }

    // interface for managing children
    public interface IItemWithChildren
    {
        Item NewChildItem();
        List<Item> GetChildItemsTypeless();
    }

    public static void Test()
    {
        // Lets build some Items with an hierarchy
        ItemA a = new ItemA();
        ItemB b = (ItemB)a.NewChildItem(); // We cast here to explicit type to show that it's working.
        Item b2 = a.NewChildItem(); // Here we got our anonymous Item
        ItemC c = (ItemC)b.NewChildItem();
        Item c2 = b.NewChildItem();

        // Lets build an anonymous list - like your args-object
        List<Item> items = new List<Item>() {a, b, b2, c, c2};

        // some target for our new children..
        List<Item> allItems = new List<Item>();

        // let's add some children
        foreach (Item item in items)
        {
            allItems.Add(item);
            IItemWithChildren itemWithchildren = item as IItemWithChildren;

            if (itemWithchildren != null)
                allItems.Add(itemWithchildren.NewChildItem());
        }

        Console.WriteLine(" - - - Items with their children - - -");
        foreach (Item item in allItems)
        {
            IItemWithChildren itemWithchildren = item as IItemWithChildren;
            Console.WriteLine(item.Name + (itemWithchildren != null ? ": " + String.Join(", ", itemWithchildren.GetChildItemsTypeless().Select(s => s.Name)) : ""));
        }
        Console.WriteLine(" - - - Items by hierarchy - - -");
        PrintItem(a);
    }

    public static void PrintItem(Item i, int level = 1)
    {
        Console.WriteLine(" ".PadRight(level*4) + i.Name);
        IItemWithChildren itemWithchildren = i as IItemWithChildren;
        if (itemWithchildren != null)
        {
            foreach (Item x in itemWithchildren.GetChildItemsTypeless())
            {
                PrintItem(x, level + 1);
            }
        }
    }

Item是你的&#34;大师班&#34;有一些商业逻辑。

ItemWithChildren<T>类,其中包含可生成新子项的业务逻辑。 IItemWithChildren是管理界面,知道你有孩子。

NewchildItem移到摘要ItemWithChildren,您甚至不需要知道任何地方的课程。 在不知道IItemWithChildren

的确切通用参数T的情况下添加子项需要接口ItemWithChildren<T>