我可以使用泛型方法作为一种模板模式吗?

时间:2012-01-23 12:14:34

标签: c# .net generics design-patterns

您好,我不确定通用方法是解决问题的正确方法。我需要解析XML文件并从中读取项目。项目可以是orderLines,notes,attachments之类的东西。获得这些项目的基本步骤都是一样的。如何制作1方法来创建这些项目的列表并调用特定方法来读取项目?

    public override IList<T> GetItems<T>(XPathNavigator currentOrder) where T : ISortableByLineNumber, new ()
    {
        var itemList = new List<T>();
        var itemXmlNodes = currentOrder.Select(OrderXPath);
        if (itemXmlNodes == null)
            throw new Exception("");
        var lineNumber = 1;
        foreach (XPathNavigator itemXmlNode in itemXmlNodes)
        {
            var item = new T();
            item = ReadItem(itemXmlNode, lineNumber++, item);
            itemList.Add(item);
            Logger.Debug(string.Format("Added item {0}", item));
        }
        return itemList;
    }

我以为我可以用ReadItem方法做到这一点。我会为我正在阅读的每种类型的项目创建重载。

    private ISortableByLineNumber ReadItem(XPathNavigator itemXmlNode, int i, OrderLine item)
    {
        // specific code to read a orderLine
    }

    private ISortableByLineNumber ReadItem(XPathNavigator itemXmlNode, int i, Note item)
    {
        // specific code to read a note
    }

但是当我尝试编译时,我可以得到“最好的重载方法匹配'XmlOrderParser.XmlOrders.Prs3XmlFileWithOrders.ReadItem(System.Xml.XPath.XPathNavigator,int,XmlOrderParser.Entities.OrderLine)'有一些无效的参数”。问题是编译器不知道如何将T转换为OrderLine或Note。

3 个答案:

答案 0 :(得分:2)

如果您使用的是.NET 4,则只需更改一件就可以使用新的dynamic类型:

dynamic item = new T(); // instead of var item = new T();

因为item现在是dynamic,运行时会根据项目的实际类型自动重载解决方案。
请注意,如果T是一种不存在过载的类型,您将收到运行时异常。


以下代码段演示了您的问题(粘贴到LINQPad并选择“C#program”作为语言):

void Main()
{
    Method<Class1>(); // Outputs Class1
    Method<Class2>(); // Outputs Class2
    Method<Class2b>(); // Outputs Class2, because it falls back to the base type
    Method<Class3>(); // Throws exception
}

void Method<T>() where T : new()
{
    dynamic c = new T();
    Method(c);
}

void Method(Class1 c) { Console.WriteLine("Class1"); }
void Method(Class2 c) { Console.WriteLine("Class2"); }

class Class1 {}
class Class2 {}
class Class2b : Class2 {}
class Class3 {}

答案 1 :(得分:0)

那是因为在编译时你不知道你需要的方法。要解决此问题,您需要找到正确的方法并调用它。尝试类似:

MethodInfo mi = typeof(YourClass).GetMethod("ReadItem",
    BindingFlags.NonPublic,
    null,
    new Type[] { typeof(XPathNavigator), typeof(int), typeof(T) },
    null);
item = mi.Invoke(this, new object { itemXmlNode, lineNumber++, item });

希望它有所帮助。祝你好运!

答案 2 :(得分:0)

正如您在评论中所说,您的所有类OrderLine,Note等都实现了ISortableByLineNumber接口,因此您可以将方法ReadItem的定义更改为:

private OrderLine ReadItem(XPathNavigator itemXmlNode, int i, ISortableByLineNumber item)
{

}

并且在上面的方法中传递给item param的实际类型将在运行时执行其特定的实现,因此如果item从{{OrderLine传递时类型为GetItems<T> 1}}方法然后调用它的具体实现等等。

方法定义中的上述更改将使您的方法定义接口具体而不具体具体类型,这是下面链接中解释的interface based编程实践之一:

http://visualstudiomagazine.com/articles/2010/01/01/interface-based-programming.aspx

What exactly is "interface based programming"?