Языки разработки c
динамической типизацией, как Python,
JavaScript,
PHP
и
другие, мне импонируют; в частности, одна из статей посвящена возможностям
языка Python в C#
("ИспользованиеIronPython
в C#"). Но в данной статье речь пойдет о динамических возможностях
именно языка C#.
В C#
динамическая типизация представлена с помощью типа dynamic и
классов DynamicObject
и
ExpandoObject.
Отличие DynamicObject
от
ExpandoObject
небольшое,
и оно зависит исключительно от объема проделанной работы. Для DynamicObject ее
нужно проделать больше, так как нужно переопределить методы TryGetMember, TrySetMember и
TryInvokeMember.
Но поскольку человек - существо довольно ленивое, пойдем
от простого сценария и рассмотрим динамические возможности языка на примере ExpandoObject.
static void Main(string[] args)
{
dynamic expandoObject = new ExpandoObject();
expandoObject.FirstName = "Aleksandr";
expandoObject.LastName = "Polukhovich";
expandoObject.FullName = expandoObject.FirstName + " " + expandoObject.LastName;
expandoObject.MethodResult = (Func<int, int>)(i => i*i);
expandoObject.PrintToConsole = (Action)(() => Console.WriteLine("Test"));
expandoObject.PrintWithParam = (Action<string>)(Console.WriteLine);
Console.WriteLine(expandoObject.FirstName);
Console.WriteLine(expandoObject.LastName);
Console.WriteLine(expandoObject.FullName);
expandoObject.PrintToConsole();
Console.WriteLine(expandoObject.MethodResult(3));
expandoObject.PrintWithParam("Test ExpandoObject");
Console.ReadLine();
}
Выше приведён пример
для создания динамического объекта и демонстрирующий, как можно задать
необходимые свойства на лету. Добавление свойств осуществляется легко, быстро и в каком угодно количестве.
expandoObject.FirstName = "Aleksandr";
expandoObject.LastName = "Polukhovich";
expandoObject.FullName
= expandoObject.FirstName + " " +
expandoObject.LastName;
Добавление
новых функций также выполняется достаточно просто.
expandoObject.MethodResult = (Func<int, int>)(i => i*i);
expandoObject.PrintToConsole = (Action)(() => Console.WriteLine("Test"));
expandoObject.PrintWithParam = (Action<string>)(Console.WriteLine);
Мы можем
также простые функции добавлять к нашему объекту.
expandoObject.HelloFunction =
Test();
Console.WriteLine(expandoObject.HelloFunction);
Для более
сложных функций необходимо приведение к нужному типу делегата.
public static int Test(int i, int j, int v)
{
return i + j + v;
}
Использование
данной функции будет иметь следующий вид:
dynamic testFunction = new ExpandoObject();
testFunction.Sum = (Func<int, int, int, int>) Test;
Console.WriteLine(testFunction.Sum(1,1,1));
Одно из
преимуществ использования динамических типов - в том, что IntelliSense в Visual Studio 2012 уже хоть немного начал работать в пределах одного метода. Раньше
с этим было проблематично.
На
заметку: если Вы планиуете использовать в своем проекте динамические
возможности языка C#,
то стоит помнить о нескольких особенностях:
- Отсутствие поддержки IntelliSense.
- Динамическая типизация работает медленно, так как работает через рефлексию.
- Очень велика вероятность допустить ошибку при разработке.
public class ElasticObject : DynamicObject
{
private Dictionary<object, object> _results = new Dictionary<object, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if
(_results.ContainsKey(binder.Name))
{
result = _results[binder.Name];
return true;
}
result = "Property not found";
return false;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
var del = (Delegate) _results[binder.Name];
result = del.DynamicInvoke(args);
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if
(!_results.ContainsKey(binder.Name))
_results.Add(binder.Name, value);
else
_results[binder.Name] = value;
return true;
}
}
Использование нашего класса ElasticObject:
static void Main(string[] args)
{
dynamic expandoObject = new ElasticObject();
expandoObject.FirstName = "Aleksandr";
expandoObject.LastName = "Polukhovich";
expandoObject.FullName = expandoObject.FirstName + " " + expandoObject.LastName;
expandoObject.MethodResult = (Func<int, int>)(i => i * i);
expandoObject.PrintToConsole = (Action)(() => Console.WriteLine("Test"));
expandoObject.PrintWithParam = (Action<string>)(Console.WriteLine);
Console.WriteLine(expandoObject.FirstName);
Console.WriteLine(expandoObject.LastName);
Console.WriteLine(expandoObject.FullName);
expandoObject.PrintToConsole();
Console.WriteLine(expandoObject.MethodResult(3));
expandoObject.PrintWithParam("Test ExpandoObject");
Console.ReadLine();
}
Использование
динамических возможностей в C#
-
очень мощная вещь, но за это мы платим производительностью. Поэтому задумайтесь
об использовании этих возможностей в своей программе, возможно, есть другое
решение, которое не подразумевает использование динамических типов данных.
Надеюсь, что данное краткое руководство поможет Вам в использовании
динамических свойств языка С#
и сделает Ваше программное обеспечение более гибким.
No comments:
Post a Comment