2015-03-04 4 views
-1

ПРИМЕЧАНИЕ: Извините заранее, если этот вопрос может быть не самым ясным, однако я пытаюсь что-то сделать, но у меня нет знаний, необходимых для того, чтобы выразить мою идею в полном объеме. Я написал здесь, чтобы узнать более продвинутый способ реализовать мою идею.Как разрешить изменения способа вызова методов без перекомпиляции каждый раз?

У меня есть несколько объектов, которые следуют интерфейс, как это

interface IObj{ 

void Parse(string document)  

string Read(string locationId) 
void Write(string locationId, string valuetoWrite) 

} 

Эти объекты все представляют структуры текста документа. Некоторые могут быть CSV-форматом, другой объект может быть XML и т. Д.

Эти объекты и другие подобные им приходят к методу обработки по одному за раз. Для каждого из разных объектов, которые я обрабатываю, я читаю инструкцию из XML конфигурации для этого объекта. Инструкции являются простыми для чтения или записи на объект.

<String Type="ObjectA"> 
    <ObjALocation id="1" Field="2" /> 
    <ObjALocation id="2" Field="4" /> 
    <ObjALocation id="3" Field="6" /> 
    </String> 

    <Processor Name="ReadValue" Type="ObjectA"> 
    <Read resultid="1" locationid="1"></Read> 
    <Read resultid="2" locationid="2"></Read> 
    <Read resultid="3" locationid="4"></Read> 

    <Output Path="C:\"> 
     <Filename extension="csv"> 
     <![CDATA[output]]> 
     </Filename> 
     <outputString> 
     <result id="1"/> , <result id="2"/> \r\n 
     </outputString> 
    </Output> 
    </Processor> 

Но говорят, завтра пользователь хочет изменить файл конфигурации таким образом, чтобы читать и писать в другом порядке,

<String Type="ObjectA"> 
    <ObjALocation id="1" Field="12" /> 
    <ObjALocation id="2" Field="34" /> 
    <ObjALocation id="3" Field="45" /> 
    </String> 

    <Processor Name="ReadValue" Type="ObjectA"> 
    <Read resultid="1" locationid="12"></Read> 
    <Read resultid="2" locationid="34"></Read> 
    <Write resultid="3" locationid="4"> 
     string to write 
    </Write> 
..... 
    </Processor> 

В моем приложении я думаю, мне нужно будет основной метод, называемый процесс(), где я буду выполнять всю инструкцию, определенную в конфигурации XML.

Так, например, что-то вроде этого

void Processor(){ 

    Read(); 
    Read(); 
    Write(); 

} 

Однако обычно вам придется предопределить инструкцию перед компиляцией приложения. Таким образом, методы и их порядок будут исправлены в методе Processor(). Но я не хочу жестко кодировать инструкцию для вызова метода чтения и записи. Я хочу дать конечному пользователю возможность вызывать эти методы в любом порядке и комбинации, которые они хотят. (Путем изменения конфигурации XML или с использованием графического интерфейса)

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

EDIT: Есть ли способ сделать это, используя любые ключевые слова C#, такие как Func, Action или dynamic. Я пытаюсь избежать использования опции компиляции динамического кода.

Есть две проблемы для меня, которые идут вместе, Как получить экземпляры чтения и записи в методе Processor(), как описано выше. И также как получить их в метод Processor() динамическим способом каждый раз, когда я вызываю Processor() - потому что завтра Processor() может обрабатывать совершенно другой объект с другой конфигурацией read() и write() ,

+1

Вы не должны удалить и повторно задать свой вопрос только потому, что он был закрыт: http://stackoverflow.com/questions/28865578/how-do-i-write-code-to-allow-changes-to-way-methods-are-called-without-recom – Servy

+0

@Servy почему бы не попросить прояснить, а не закрыть так быстро? – erotavlas

+0

@Servy я не понимаю, что неясно по вопросу – erotavlas

ответ

1

Вы ищете функцию под названием reflection.

Вы можете получить информацию о времени выполнения для типа объекта, вызвав его метод GetType(). Затем вы можете получить конкретный метод от Type, позвонив GetMethod(string name) или GetMethods. Если у вас есть метод MethodInfo для метода, который вы хотите вызвать, вы можете вызвать его с помощью метода Object Invoke(Object, [Object]). Первый аргумент Invoke - это объект, для которого нужно вызвать метод, а второй аргумент - массив аргументов для перехода к методу.

Было бы разумно защитить ваш код от выполнения произвольных методов, отметив эти методы, которые могут быть выполнены из файла конфигурации с помощью Attribute и проверки наличия этого атрибута перед вызовом метода.

+0

Я не думаю, что он ищет отражение. По сути, его xml просто содержит порядок и аргументы для методов, которые он уже реализовал. – aush

+0

Спасибо за предложение и за указание об использовании атрибутов для предотвращения нежелательных вызовов методов – erotavlas

2

Для входа

<Root> 
    <Processor Name="ReadValue" Type="ObjectB"> 
     <Read resultid="1" locationid="12"></Read> 
     <Read resultid="2" locationid="34"></Read> 
     <Write resultid="3" locationid="4"> 
      string to write 
     </Write> 
    </Processor> 
    <Processor Name="ReadValue" Type="ObjectA"> 
     <Read resultid="1" locationid="12"></Read> 
     <Read resultid="2" locationid="34"></Read> 
     <Write resultid="3" locationid="4"> 
      string to write 
     </Write> 
    </Processor> 
</Root> 

ваш код может выглядеть следующим образом:

void Main() 
{ 
    var xDoc = XDocument.Load(@"C:\PathToXml\instructions.xml"); 

    foreach (var processor in xDoc.Root.Elements()) 
    { 
     if (processor.Attribute("Name").Value == "ReadValue") 
     { 
      var readValueProcessor = new ReadValueProcessor(); 
      readValueProcessor.Execute(processor); 
     } 
    } 
} 

interface IObj 
{ 
    string Read(int resultid, int locationid); 
    void Write(int resultid, int locationid, string text); 
} 

class ObjectA : IObj 
{ 
    public string Read(int resultid, int locationid) 
    { 
     return resultid + " " + locationid + " From A"; 
    } 

    public void Write(int resultid, int locationid, string text) 
    { 
     Console.WriteLine(resultid + " " + locationid + " From A : " + text); 
    } 
} 

class ObjectB : IObj 
{ 
    public string Read(int resultid, int locationid) 
    { 
     return resultid + " " + locationid + " From B"; 
    } 

    public void Write(int resultid, int locationid, string text) 
    { 
     Console.WriteLine(resultid + " " + locationid + " From B : " + text); 
    } 
} 

class ReadValueProcessor 
{ 
    public void Execute(XElement processorNode) 
    { 
     var typeAttribute = processorNode.Attribute("Type").Value; 
     IObj objectToExecute = null; 

     if (typeAttribute == "ObjectA") 
     { 
      objectToExecute = new ObjectA(); 
     } 
     else if (typeAttribute == "ObjectB") 
     { 
      objectToExecute = new ObjectB(); 
     } 

     foreach (var action in processorNode.Elements()) 
     { 
      if (action.Name == "Read") 
      { 
       var resultid = int.Parse(action.Attribute("resultid").Value); 
       var locationid = int.Parse(action.Attribute("locationid").Value); 
       var result = objectToExecute.Read(resultid, locationid); 
       Console.WriteLine(result); 
      } 
      else if (action.Name == "Write") 
      { 
       var resultid = int.Parse(action.Attribute("resultid").Value); 
       var locationid = int.Parse(action.Attribute("locationid").Value); 
       var text = action.Value; 
       objectToExecute.Write(resultid, locationid, text); 
      } 
     } 
    } 
} 
+0

https://dotnetfiddle.net/KShULd – aush

+0

Спасибо, это дает мне возможность попробовать. Я, вероятно, сохранил десериализацию XML отдельно от обработки. То есть Вероятно, я бы не назвал процессор в каждом элементе xml, я бы десериализовал объекты и использовал его в процессоре. – erotavlas

+0

@erotavlas уверен, вы определенно должны отделить эти шаги. Я просто дал вам упрощенный пример этой идеи. – aush

Смежные вопросы