Reflectioning

12 отговора 439 прегледа
#1

Reflectioning

Дайте някаква информация за reflectioning-a.
Къде точно може да намери той приложение?
И на някой налагало ли му се е да го използва, ако да, къде?

Отговор
в отговор на Memo #2

Re: Reflectioning

Reflection, a не Reflectioning

а) виж MSDN
б) да, често, за late binding и aspect-oriented дивотии

Редактирано от gruhal на

Отговор
в отговор на Memo #3

Обикновено

когато работя с ресурси (а при мене е постоянно !)
Това е обръщение към асемблито което се изпълнява в момента- например ;-)
"System.Reflection.Assembly.GetExecutingAssembly"

А това е конкретен (леко изменен) пример:
"m_objResourceManager = New ResourceManager("My_FrameworkResources", System.Reflection.Assembly.GetExecutingAssembly)"

UB40 !
Отговор
в отговор на Memo #4

Re: Reflectioning

Reflection дава възможност на една програма динамично да анализира и открива елементи (като fields, methods, constructors, attributes) на типове (като класове, интерфейси, структури) във вече съществуващи асемблита, тъй като всеки компилатор който генерира CLR код, генерира и metadata която описва съответните елементи. Като получим тази информация, може просто да я покажем (decompilers, class browsers, object inspectors) или да инстанциираме и извикваме функционалност по много динамичен начин. Reflection не се ограничава само до анализ на съществуващ компилиран код. Може да се използва за генериране на нови типове изцяло в паметта и пак да ги извикваме като обикновен код. Например: код който изучава функционалноста на един интерфейс и му генерира динамично wrapper class (познато още като adapter или proxy). Това се използва в .NET remoting architecture, която на мене ми била супер мътна според много хора в този форум.
Ако тази идея за self-generating code се развие достатъчно завбъдеще, програмата може да стане автор на самата себе си и тя да решава как ще се изпълянва. Нещо като The Matrix ... така един алгоритъм може да се изгради динамично без изобщо да е писан от програмист или да се съхранява на сорс файл, примерно generic algorithms които сами си модифицират поведението за да намерят решение на трудна математическа задача.

На пръв поглед reflection може да изглежда трудно за разбиране или ненужно, обаче много tools като IntelliSense, Class View, Property Windows използват reflection особено усилено :)). Освен това .Net Framework го използва за object serialization, the .NET remoting architecture, and dynamic method dispatch. Всъщност виртуално всяка една .net програма използва reflection по много начини без даже програмиста да осъзнава за това.

Най-важен в цялата тази работа е класа Type. Той съдържа информация (metadata) за останалите типове. Но в същността си е просто един тип клас най-обикновен, малко абстрактен но пък ти позволява достъп то metadata-а на другите класове.

Как работи цялата тази работа:

Най-важното е че всеки тип наследяващ Object поддържа GetType метода, който ти връща обект от тип Type.

Type* Object::GetType()

Type класа има много методи, можеш да ги видиш в документацията, обаче ми е съвестно ако не се спра на най-важните:

Можеш да вземеш типа на даден клас чрез името му:

Type* Type::GetType(String* typeName)

или атрибутите му:

TypeAttributes Type::get_Attributes()

или базовия клас:

Type* Type::get_BaseType()

или всичките му методи:

MethodInfo* Type::GetMethods() []

и така нататък ...

За да рефлектираш определен тип, първо трябва да заредиш асемблито му в паметта. Това става най-лесно с Assembly класа.

Assembly* Assembly::LoadFrom(String* assemblyFile)

и после си го разглеждаш както искаш, примерно:

Type* Assembly::GetTypes() []

Когато го получиш този масив, може да рефлектираш всеки тип в него като му достъпваш: MethodInfo, FieldInfo, ParameterInfo и каквото там ти трябва.

Аз лично най-често ползвам reflection за custom attributes, interface wrappers, и stored procedures wrappers ... а за stored proc-овете направо се е разбило ... нали се сещаш как се викаха stored procs от ADO ... описваш всеки параметър един по един за всяка процедура ... и в една голяма бизнес система смятай за кво писане на конвеир става въпрос ... с reflection работата с stored procedures добива нови измерения


XM TurboCT .. where comfort meets power
Отговор
в отговор на Memo #5

Re: Reflectioning

Благодаря за мненията!

Отговор
в отговор на Memo #6

Re: Reflectioning

я кажи как точно използваш рефлекшън са сторнати процедури (в SQL Server?), че не ми стана ясно?

Отговор
в отговор на pp #7

Re: Reflectioning

не използва рефлекшън точно със самите сторнати процедури (предполагам), а им генерира параметер байндинга он дъ флай. Слагаш си къстъм атрибут, който ти казва кое пропърти на обекта към кое поле на таблицата се мапва и после през рефлекшън мяташ.

(сори за кирилицата ама ме мързи да превключвам)

Отговор
в отговор на pp #8

reflection в stored procedures

Главния недостатък на ползването на SQL stored procedures от С# код е това че трявба да напаснеш (match) прекалено много типове. И се налага да пишеш дълги wrapper functions. Ако ползваш stored procedures доста, знаеш колко е досадно да описваш всеки параметър: име, тип, размер и т.н. ... освен това ако промениш процедурата и пак трябва да ходиш да променяш кода в data service layer-a. Примерно имаш следната процедура:

CREATE PROCEDURE GetData @ID int
AS
SELECT * FROM DataTable WHERE [ID] = @ID

за да извикаш тази процедура обикновенно и правиш wrapper функция като тази:

Recordset GetData(Connection cn, int nID)
{
Command cm = new Command();
cm.ActiveConnection = cn;
cm.CommandText = "GetData";
cm.CommandType = adCmdStoredProc;

Parameters params = cm.Parameters;
params.Append(cm.CreateParameter("@RETURN_VALUE", adInteger, adParamReturnValue, 0);
params.Append(cm.CreateParameter("@ID", adInteger, adParamInput, 0);
params("@ID").Value = nID;

Recordset r = new Recordset();
r.CursorLocation = adUseClient;
r.Open ( cm, , adOpenStatic, adLockReadOnly );
r.ActiveConnection = null;
return r;
}


Този подход съвсем не е зле в ерата когато нямаше .NET, обаче сега като видиш половината ти екип през половината ден да пише такъв код и после половината му рипорт да е: "Емиии ... писах wrapper functions ..." и си викаш - отиде ми и производителност и deadlines и кво ли не ... и почваш да мъдриш некви гениални идеи ... примерно: да напишеш генератор който автоматично прави wrapper functions чрез SQLDMO ... или пък да правиш XML дефиниции на процедурите и после с XSLT (за което според някой хора в този форум аз изобщо не съм бил чувал) да генерираш кода на wrapper function-a.

Но първите идеи не е задължително да са винаги най-подходящите ...

Как reflection променя цялата тази картинка ???!!!

Лесно може да си представиш как чрез reflection може да обходиш параметрите на дадена функция и да създадеш SqlCommand обект с респективните SqlParameter обекти. Всичко което трябва да направиш е да дефинираш функции които да представляват твоите процедури и останалото ще се прави от една utility function която динамично ще създава и конфигурира SqlCommand обекти по време на изпълнение на програмата за да се обръща към базата данни. Примерно нещо такова:

sealed class SqlCommandGenerator
{
private SqlCommandGenerator() {}

public static SqlCommand GenerateCommand(SqlConnection connection,
MethodInfo method, object[] values)
{
SqlCommand command = new SqlCommand(method.Name, connection);
command.CommandType = CommandType.StoredProcedure;

ParameterInfo[] parameters = method.GetParameters();

for (int i = 1; i < parameters.Length; i++)
{
SqlParameter sqlParameter = new SqlParameter();
sqlParameter.ParameterName = "@" + parameters[ i ].Name;
sqlParameter.Value = values[ i ];

command.Parameters.Add(sqlParameter);
}

return command;
}
}

Като имаш обект от тип Connection, метаданните на метода и стойностите на параметрите GenerateCommand генерира и изпълнява SqlCommand обект все едно че си го писал като сорс. Даже няма нужда да да ползвам типа на параметъра да получа SqlDbType за да дам типа на SqlParametera, защото SqlParameter вече има такава функционалност като подаваш Value и го прави вместо тебе.

След това трябва да извикаш GenerateCommand от GetData и да използваш генерираната команда:

public static DataSet GetData(SqlConnection connection, int Id)
{
MethodInfo methodInfo =
typeof(myDatabase).GetMethod("GetData",
new Type[] { typeof(SqlConnection), typeof(int) });

SqlCommand command =
SqlCommandGenerator.GenerateCommand(connection,
methodInfo, new object[] { Id });

DataSet dataSet = new DataSet();
SqlDataAdapter dataAdapter = new SqlDataAdapter(command);
dataAdapter.Fill(dataSet);
return dataSet;
}

До тук добре ... обаче не е идеално защото пак ще ти се налага да правиш промени в кода ако се промени процедурата, примерно смениш името. Това лесно може да се реши ако се разходиш по стека и вземеш frame-а на въпросния метод. Наред с всички хубави неща в FCL, има еднa особено приятна функция, леко скрита ама това да не те притеснява, MehodBase.GetCurrentMethod. Тя ти връща MethodBase (MethodInfo или ConstructorInfo) за функцията която я вика. И става нещо такова:

public static DataSet GetData(SqlConnection connection, int Id)
{
SqlCommand command = SqlCommandGenerator.GenerateCommand
(connection, (MethodInfo) MethodBase.GetCurrentMethod(),
new object[] { Id });

DataSet dataSet = new DataSet();
SqlDataAdapter dataAdapter = new SqlDataAdapter(command);
dataAdapter.Fill(dataSet);
return dataSet;
}

горе долу това е идеята макар че има случаи когато имаш безименни параметри или пък типовете на параметрите са леко различни от тези на метода или пък NULL values ... ама и те си имат решение - Attributes ...




XM TurboCT .. where comfort meets power
Отговор
в отговор на шeф нa Coди Дeвня #9

Re: reflection в stored procedures

Всъщност вече има доста добри комерсиални пакети (ORM.NET) примерно, които четат схемата от SQL Server-a и създават всички необходими wrapper класове за основните queries - Select, Update, Insert, Delete.

Аз лично ползвам безплатния LLBL Gen, потърси Гуугъл. Чете вече създадена база и генерира всички основни queries за всяка таблица във формат на сторнати процедури, плюс евентуалните joins като следи foreign keys. След това създава C# wrapper класове с обекти, представящи всяка таблица и съответните методи, които викат stored procedures layer. Доста е удобно, и макар че разбира се не хваща всички случаи, е повече от достатъчно като за начало.

А иначе идеята ти е повече от добра и интересна. Похвално е, че отделяш толкова време за такива постове, лошото е, че малко хора ги оценяват. Не се ядосвай, нивото е доста високо, и повечето пичове нямат идея за какво точно говориш. А иначе къде работиш, освен че си шеф на Соди-Девня :) ?

Отговор
в отговор на шeф нa Coди Дeвня #10

Re: reflection в stored procedures

Благодаря за изчерпателния отговор. Много хитро това бе!
А да ви питам намесваш ли някъде в цялата работа метода

SqlCommandBuilder.DeriveParameters

който изкарва имената, типовете и дали параметрите са input/output от базата?
Щото OLEDB Providera си иска параметрите по ред а пък SQL Providera си ги турси по имена. Въврви пиши независима обвивка после .

Отговор
в отговор на rr #11

Re: reflection в stored procedures

мдааа .... както казах тази идея не е напълно изчепателна тъй като не решава няколко проблема:

1. безименни параметри, тоест по ред
2. parameter's direction - input/output
3. NULL values

обаче те също си имат решение - Custom Attributes

сега точно нямам време да опиша цялата процедура надълго и широко щото следобед заминавам на море, а пък трявба да попривърша тука с работата че иначе не ме пускат , ама като се върна ще пусна един пост и за тях щото си заслужава да се види

DeriveParameters не ги ползвам защото изискват допълнителен roundtrip към сървъра ... което ми се струва скъпичко


XM TurboCT .. where comfort meets power
Отговор
в отговор на шeф нa Coди Дeвня #12

Re: reflection в stored procedures

За сторнатите процедури е по-добре да си ги издърпаме с мишката от Server Explorera, необходимия код бива генериран от Studioto.

Отговор