XML-литералы в коде VB.NET не работают с операторами #if

У меня есть проект vb.net, который использует XML-литерал для настройки панели навигации интерфейса пользователя. Код выглядит примерно так и работает уже много лет.

Private ReadOnly _actionTreeXml As XElement =
<nodes>
    <node key="any" name="Top">
        <node key="log" name="***LOGIN***" type="everybody"></node>
        <node key="op" name="Home" ctrl="uiHomePage" type="mfg"></node>
        <node key="barcode" name="Barcode Entry" ctrl="EditMfgEntry" type="mfg"></node>
        <node key="wip" name="Work in Progress" ctrl="QueryWIP" type="mfg"></node>
        <node key="readme" name="Version Info" type="everybody"></node>
    </node>
</nodes>

Недавно мне нужно было две сборки проекта, которые немного различаются (я не хочу платить за библиотечный код для многих пользователей). Итак, у меня есть одна сборка, в которой я выбрал все инструменты пользовательского интерфейса, связанные со штрих-кодом. Это прекрасно работает везде, кроме XML-литералов, подобных этому

#if USE_BAR_CODE=1
<node key="barcode" name="Barcode Entry"    ctrl="EditMfgEntry" type="mfg">  </node>
#end if

Если я установлю USE_BAR_CODE в 0, я все равно получу литерал xml внутри блока #if, но везде в моем коде, где я использовал обычный источник VB, код не был скомпилирован.

Это наводит меня на мысль, что процесс компиляции обрабатывает литералы xml ДО операторов #if. Я что-то пропустил?

2 ответа

Решение

Может быть, это совсем не решение проблемы, но, как гласит пословица: "Плохой кустарник лучше открытого поля".

Основная идея заключается в использовании узла инструкции обработки. Если элемент имеет инструкцию обработки над ним, пропустите его, в противном случае включите его. Таким образом, вы можете контролировать "инклюзивность" этого элемента.

1) Сначала создайте метод расширения:

Module XmlExtentions
    <System.Runtime.CompilerServices.Extension>
    Function Filter(root_node As IEnumerable(Of XElement)) As IEnumerable(Of XElement)
        Return root_node.First().Elements().Where(
            Function(e)
                If e.PreviousNode Is Nothing Then Return True
                Return e.PreviousNode.NodeType <> Xml.XmlNodeType.ProcessingInstruction
            End Function)
    End Function
End Module

2. Запросите наш XML:

Dim _actionTreeXml As XElement =
    <nodes>
        <node key="any" name="Top">
            <node key="log" name="***LOGIN***" type="everybody"></node>
            <node key="op" name="Home" ctrl="uiHomePage" type="mfg"></node>
            <?Skip-Element?>
            <node key="barcode" name="Barcode Entry" ctrl="EditMfgEntry" type="mfg"></node>
            <node key="wip" name="Work in Progress" ctrl="QueryWIP" type="mfg"></node>
            <node key="readme" name="Version Info" type="everybody"></node>
        </node>
    </nodes>

Dim elements = _actionTreeXml.<node>.Filter()
'// Do something...
elements.ToList().ForEach(Sub(e) Console.WriteLine(e))

К сожалению, нет, вы не можете использовать такие директивы в литералах. Под капотом поведение такое же как If, Then and Else заявления. Вы не можете поместить их непосредственно в линию, какой вы есть, вы должны обернуть блок кода, чтобы сообщить компилятору, что компилировать, а не компилировать во время выполнения, как стандарт If, Then and Else заявления. Операторы в блоке условной компиляции должны быть полными логическими операторами. Например, вы не можете условно компилировать только атрибуты литералов, функций и т. Д.

Таким образом, быстрое решение ниже, чтобы включить узел или не включать его. Это было также проверено и работает просто отлично.

#If USE_BAR_CODE = 1 Then
    Private ReadOnly _actionTreeXml As XElement = <nodes>
                                                      <node key="any" name="Top">
                                                          <node key="log" name="***LOGIN***" type="everybody"></node>
                                                          <node key="op" name="Home" ctrl="uiHomePage" type="mfg"></node>
                                                          <node key="barcode" name="Barcode Entry" ctrl="EditMfgEntry" type="mfg"></node>
                                                          <node key="wip" name="Work in Progress" ctrl="QueryWIP" type="mfg"></node>
                                                          <node key="readme" name="Version Info" type="everybody"></node>
                                                      </node>
                                                  </nodes>
#Else
    Private ReadOnly _actionTreeXml As XElement = <nodes>
                                                      <node key="any" name="Top">
                                                          <node key="log" name="***LOGIN***" type="everybody"></node>
                                                          <node key="op" name="Home" ctrl="uiHomePage" type="mfg"></node>                                                          
                                                          <node key="wip" name="Work in Progress" ctrl="QueryWIP" type="mfg"></node>
                                                          <node key="readme" name="Version Info" type="everybody"></node>
                                                      </node>
                                                  </nodes>


#End If
Другие вопросы по тегам