субота, 13 березня 2010 р.

Conditional execution architecture approach

Overview
Sometimes it is required to store execution logic without immediate execution. In this case execution can be expanded to two steps: preparation and physical execution. For example this model can be used if execution takes a lot of time or resources.

Statements
As one of solution for this problem it is proposed to use statements implementation.
According to it pattern each logical execution should be described using instance of Statement class:

public abstract class Statement

{

...

}


Any class based on Statement should represent concrete execution details, but shouldn’t include code for physical execution. For example it is possible to use following structure:














Conditional statements
Also it is proposed to implement conditional statements. These statements shouldn’t execute useful executions but should define what statements should be executed. Let’s change architecture to following











It is proposed to use two ways to implement conditional statements:
1. Conditional statements should return Boolean value.
2. Conditional statement should rise an exception if conditional is false.

Also let’s add child collection to base Statement class:

public abstract class Statement

{

public IEnumerable<Statement> ChildStatements { get; }

...

public Statement(params Statement[] childStatements)

{

...

}

}


In this case child statements should be executed only if parent statement executed without exceptions and any conditional statements are passed.

Example. Let’s describe logic for conditional statements. We should write to file some string only if this file accessible.
Statements for actions should be already implemented:

public abstract class Statement

{

public IEnumerable<Statement> ChildStatements { get; }

public Statement(params Statement[] childStatements)

{

}

}

public abstract class ExecutionStatement : Statement

{

}

public abstract class ConditionalStatement : Statement

{

public ConditionalStatement()

{

}

public ConditionalStatement(params Statement[] childStatements) : base(childStatements);

{

}

}

public abstract class FileManipulationsStatement : ExecutionStatement

{

public string FileName { get; set; }

}

public class WriteFileDataStatement : FileManipulationsStatement

{

public string Data { get; set; }

}

public class FileAccesibleConditionalStatement : ConditionalStatement

{

public FileAccesibleConditionalStatement()

{

}

public FileAccesibleConditionalStatement(params Statement[] childStatements) : base(childStatements);

{

}

}

Let’s create Write statement:


WriteFileDataStatement write = new WriteFileDataStatement();


Let’s create FileAccessible conditional statement for this:

FileAccesibleConditionalStatement fa = new FileAccesibleConditionalStatement(write);


Physical execution

This approach makes possible to easy define execution statements but doesn’t account physical execution.

It is proposed to use associated classed for each statement for physical execution. I am going to describe this approach in next article.


This article also available:

пʼятниця, 30 травня 2008 р.

Динамическая загрузка и использование сборок. Reflection

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

Я покажу простой пример, как это можно сделать:

Предположим, что у нас есть некая сборка cl, которая включает в себя класс Class1:


using System;

namespace cl
{
public class Class1
{
public void Write()
{
Console.Write("Hello, world!");
}
}
}

Скомпилируем сборку и положим ее, например, на c:\cl.dll

Далее попробуем динамически подгрузить эту библиотеку и вызвать метод Write()

Получаем:
using System;
using System.Reflection;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Assembly asm = Assembly.LoadFile("c:\\cl.dll");
object cl = asm.CreateInstance("cl.Class1");
Type clType = cl.GetType();
MethodInfo method = clType.GetMethod("Write");
method.Invoke(cl, null);
}
}
}

Если методу требуется передать какие либо параметры, тогда следует передать их в методе Invoke() экземпляра MethodInfo.
Делается это так:

method.Invoke(cl, new object[] {"Some argument"});


Вот так все просто :)

Правда, применять это следует с осторожностью. Во первых, reflection работает довольно медленно, во вторых - таким образом можно создать массу дыр в безопасности.
Кстати, вопросы производительности очень хорошо описаны в статье тут: http://rsdn.ru/article/dotnet/reflectionspeed.xml