Могу ли я использовать универсальный метод в качестве шаблона шаблона? - PullRequest
2 голосов
/ 23 января 2012

Привет, я не уверен, что универсальный метод - верный способ решить мою проблему. Мне нужно проанализировать файл XML и прочитать элементы из него. Предметами могут быть такие вещи, как строки заказа, заметки, вложения. Основные шаги для получения этих предметов одинаковы. Как я могу создать 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 ]

2 голосов
/ 23 января 2012

Если вы используете .NET 4, вы можете использовать новый тип dynamic, изменив только одну вещь:

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

Поскольку item теперь равно dynamic, среда выполнения выполняет автоматическийРазрешение перегрузки на основе фактического типа элемента.
Обратите внимание, что вы получите исключение runtime , если 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 {}
0 голосов
/ 23 января 2012

Как вы сказали в комментарии, все ваши классы OrderLine, Note и т. Д. Реализуют интерфейс ISortableByLineNumber, поэтому вы можете изменить определение вашего метода ReadItem на:

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

}

и фактический тип, которыйпередается параметру item в вышеприведенном методе, его конкретная реализация будет выполняться во время выполнения, поэтому, если item имеет тип OrderLine при передаче из метода GetItems<T>, то будет вызываться его конкретная реализация и т. д.

Вышеуказанное изменение в определении метода сделает ваш интерфейс определения метода конкретным, а не конкретным типом, что является одной из практик программирования interface based, описанных в следующих ссылках:

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

Что такое «интерфейсное программирование»?

0 голосов
/ 23 января 2012

Это потому, что во время компиляции вы не знаете, какой метод вам понадобится.Чтобы решить эту проблему, вам нужно найти правильный метод и вызвать его.Попробуйте что-то вроде:

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 });

Надеюсь, это поможет.Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...