У меня есть .NET сборка. Надо получить список статических методов в типах из этой сборки, в которых есть обращения к статическим полям. Как это быстрее и проще всего сделать?
Здравствуйте, Oksana Gimmel, Вы писали:
OG>У меня есть .NET сборка. Надо получить список статических методов в типах из этой сборки, в которых есть обращения к статическим полям. Как это быстрее и проще всего сделать?
Можно с помощью Microsoft.Cci. Вот так можно найти записи стат. полей:
static void Main(string[] args) {
const string LOCATION = @"....";
var assemblyNode = AssemblyNode.GetAssembly(LOCATION, true, true, false);
var q = from t in assemblyNode.Types
from m in t.Members.OfType<Method>()
where m.IsStatic && HasStaticFieldWrite(m)
select m;
foreach (Method method in q) {
Console.WriteLine(method.FullName);
}
}
static bool HasStaticFieldWrite(Method method) {
var q = from st in method.Body.Statements.SelectMany(GetChildStatements).OfType<AssignmentStatement>()
let mb = st.Target as MemberBinding
where mb != null
let f = mb.BoundMember as Field
where f != null && (f.IsStatic)
select st;
return q.Any();
}
static IEnumerable<Statement> GetChildStatements(Statement statement) {
var block = statement as Block;
return block != null ? block.Statements : Enumerable.Empty<Statement>();
}
Здравствуйте, Oksana Gimmel, Вы писали:
OG>У меня есть .NET сборка. Надо получить список статических методов в типах из этой сборки, в которых есть обращения к статическим полям. Как это быстрее и проще всего сделать?
Быстрее всего написать визитор (унаследовав от BaseCodeTraverser) и проверять ITargetExpression и IBoundExpression на наличие таких обращений.
Здравствуйте, gandjustas, Вы писали:
G>Быстрее всего написать визитор (унаследовав от BaseCodeTraverser) и проверять ITargetExpression и IBoundExpression на наличие таких обращений.
Здравствуйте, Sinix, Вы писали:
L>>Можно с помощью Microsoft.Cci. Вот так можно найти записи стат. полей:
S>Позанудствую. let лучше заменить на select ... into (а ещё лучше цепочку из let where let where превратить в отдельный фильтр-метод).
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, gandjustas, Вы писали:
G>>Быстрее всего написать визитор (унаследовав от BaseCodeTraverser) и проверять ITargetExpression и IBoundExpression на наличие таких обращений.
S>Будет неудобно получать список.
Здравствуйте, gandjustas, Вы писали:
OG>>У меня есть .NET сборка. Надо получить список статических методов в типах из этой сборки, в которых есть обращения к статическим полям. Как это быстрее и проще всего сделать?
G>Быстрее всего написать визитор (унаследовав от BaseCodeTraverser) и проверять ITargetExpression и IBoundExpression на наличие таких обращений.
Мне интересно, чем ты руководствовался, когда писал такой ответ? Ничего же непонятно. Непонятно даже, какое отношение имеют твое сообщение к вопросу.
Здравствуйте, Lloyd, Вы писали:
S>>Позанудствую. let лучше заменить на select ... into (а ещё лучше цепочку из let where let where превратить в отдельный фильтр-метод).
L>Не считаю, что это лучше.
Каковы ваши доказатьельства?(с)
Мои:
1) let заводит новый анонимный тип, что оочень хорошо просаживает нанотесты (в реальном коде, конечно, найдётся чему тормозить и без них). В общем случае лучше обойтись без let.
2) Вынесение цепочки let where в отдельный метод позволяет превратить нагромождение итераторов в пару if'ов.
Здравствуйте, Тролль зеленый и толстый, Вы писали:
ТЗИ>Почитал твои ссылки и не понял, почему это лучше.
Не лучше. let имеет неприятные side-эффекты (неявное создание анонимных типов) и повсевместно использоваться не должен.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, gandjustas, Вы писали:
OG>>>У меня есть .NET сборка. Надо получить список статических методов в типах из этой сборки, в которых есть обращения к статическим полям. Как это быстрее и проще всего сделать?
G>>Быстрее всего написать визитор (унаследовав от BaseCodeTraverser) и проверять ITargetExpression и IBoundExpression на наличие таких обращений.
L>Мне интересно, чем ты руководствовался, когда писал такой ответ? Ничего же непонятно. Непонятно даже, какое отношение имеют твое сообщение к вопросу.
Чтобы получить любое обращение к статическому полю надо писать визитор. Соответственно визитор можно натравливать на каждый статический метода каждого типа.
Задача получения всех методов всех типов решается тривиально с помощью CCI, а поиск обращения к статическому полю — как написал выше.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, gandjustas, Вы писали:
G>>Прогонять визитором каждый метод — очень удобно. S>Как это поможет решить исходную задачу?
Здравствуйте, Sinix, Вы писали:
S>Каковы ваши доказатьельства?(с) S>Мои: S>1) let заводит новый анонимный тип, что оочень хорошо просаживает нанотесты (в реальном коде, конечно, найдётся чему тормозить и без них). В общем случае лучше обойтись без let.
Это детали реализации. Для меня лучшая читаемость имеет более высокий приоритет, тем более, что в реале ты разницу и в микроскоп не заметишь.
S>2) Вынесение цепочки let where в отдельный метод позволяет превратить нагромождение итераторов в пару if'ов.
Вынесение позволяет позволяет превратить пару let-ов в нагромождение методов.
Здравствуйте, gandjustas, Вы писали:
L>>Мне интересно, чем ты руководствовался, когда писал такой ответ? Ничего же непонятно. Непонятно даже, какое отношение имеют твое сообщение к вопросу.
G>Чтобы получить любое обращение к статическому полю надо писать визитор. Соответственно визитор можно натравливать на каждый статический метода каждого типа.
Зачем так сложно? Где в моем примере визитор?
G>Задача получения всех методов всех типов решается тривиально с помощью CCI,
Ты действительно думаешь, что топикстартер знал о существовании Cci и при этом не знает как выдрать нужные методы?
G>а поиск обращения к статическому полю — как написал выше.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, gandjustas, Вы писали:
L>>>Мне интересно, чем ты руководствовался, когда писал такой ответ? Ничего же непонятно. Непонятно даже, какое отношение имеют твое сообщение к вопросу.
G>>Чтобы получить любое обращение к статическому полю надо писать визитор. Соответственно визитор можно натравливать на каждый статический метода каждого типа. L>Зачем так сложно? Где в моем примере визитор?
Твой пример далеко не все случаи покрывает, только в левой части оператора присваивания.
G>>Задача получения всех методов всех типов решается тривиально с помощью CCI, L>Ты действительно думаешь, что топикстартер знал о существовании Cci и при этом не знает как выдрать нужные методы?
Я думаю теперь уже знает.
G>>а поиск обращения к статическому полю — как написал выше. L>Вот и написал бы код, если все так просто.
Чуть позже, некогда было.
Здравствуйте, gandjustas, Вы писали:
G>>>Чтобы получить любое обращение к статическому полю надо писать визитор. Соответственно визитор можно натравливать на каждый статический метода каждого типа. L>>Зачем так сложно? Где в моем примере визитор?
G>Твой пример далеко не все случаи покрывает, только в левой части оператора присваивания.
Неужели?
Вот так можно найти записи стат. полей
Да и как этот ответ связан с использованием визитора?
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, gandjustas, Вы писали:
G>>>>Чтобы получить любое обращение к статическому полю надо писать визитор. Соответственно визитор можно натравливать на каждый статический метода каждого типа. L>>>Зачем так сложно? Где в моем примере визитор?
G>>Твой пример далеко не все случаи покрывает, только в левой части оператора присваивания.
L>Неужели? L>
L>Вот так можно найти записи стат. полей
Исходная то задача была:
Надо получить список статических методов в типах из этой сборки, в которых есть обращения к статическим полям.
А твой пример не расширяется до поиска любого обращения.
Здравствуйте, Lloyd, Вы писали:
G>>А твой пример не расширяется до поиска любого обращения.
L>Почему не расширяется? Допиши нужную логику в HasStaticFieldWrite и всех делов-то.
Ну допиши
L>Кстати, ты попустил вопрос: L>
L>Да и как этот ответ связан с использованием визитора?
Здравствуйте, gandjustas, Вы писали:
G>>>А твой пример не расширяется до поиска любого обращения.
L>>Почему не расширяется? Допиши нужную логику в HasStaticFieldWrite и всех делов-то. G> Ну допиши
Ну допишу. Ты в это время свой вариант не забудь подготовить.
L>>Кстати, ты попустил вопрос: L>>
L>>Да и как этот ответ связан с использованием визитора?
G>Как допишешь — так узнаешь
Да уж сообщи мне, если знаешь. Вдруг ты действительно прав.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, gandjustas, Вы писали:
G>>>>А твой пример не расширяется до поиска любого обращения.
L>>>Почему не расширяется? Допиши нужную логику в HasStaticFieldWrite и всех делов-то. G>> Ну допиши
L>Ну допишу. Ты в это время свой вариант не забудь подготовить.
public class FindStaticReferencesVisitor: BaseCodeTraverser
{
public static bool HasStaticReferences(IMethodDefinition method)
{
var visitor = new FindStaticReferencesVisitor();
visitor.Visit(method);
return visitor.staticReferences.Any();
}
List<ITypeDefinitionMember> staticReferences = new List<ITypeDefinitionMember>();
public override void Visit(ITargetExpression targetExpression)
{
CollectStaticReferences(targetExpression.Definition);
base.Visit(targetExpression);
}
public override void Visit(IBoundExpression boundExpression)
{
CollectStaticReferences(boundExpression.Definition);
base.Visit(boundExpression);
}
private void CollectStaticReferences(object definition)
{
if (definition is IFieldDefinition)
{
var fieldDef = definition as IFieldDefinition;
if (fieldDef.IsStatic)
{
staticReferences.Add(fieldDef);
}
}
if (definition is IPropertyDefinition)
{
var propertyDef = definition as IPropertyDefinition;
if (propertyDef.Accessors.Select(a => a.ResolvedMethod).All(m => m.IsStatic))
{
staticReferences.Add(propertyDef);
}
}
}
}
class Program
{
static string assemblyName;
static void Main(string[] args)
{
assemblyName = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
var host = new CodeContractAwareHostEnvironment();
IAssembly assembly = host.LoadUnitFrom(assemblyName) as IAssembly;
if (assembly == null || assembly == Dummy.Assembly)
{
Console.WriteLine("Error");
}
else
{
var codeAssembly = Decompiler.GetCodeModelFromMetadataModel(host, assembly, null);
var q = from t in codeAssembly.AllTypes
from m in t.Methods
where FindStaticReferencesVisitor.HasStaticReferences(m)
select m;
var method = q.First();
Console.WriteLine(method.Name);
}
}
}
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, gandjustas, Вы писали:
G>>Вот как-то так.
L>Да, действительно, самому читать — чрезчур много писанины получается.
Это "чрезчур много писанины" называется визитором.
Здравствуйте, gandjustas, Вы писали:
L>>Да, действительно, самому читать — чрезчур много писанины получается.
G>Это "чрезчур много писанины" называется визитором.
G>Вот и ответ на твой вопрос.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, gandjustas, Вы писали:
L>>>Да, действительно, самому читать — чрезчур много писанины получается.
G>>Это "чрезчур много писанины" называется визитором.
G>>Вот и ответ на твой вопрос.
L>Нет, визитор тут не причем.
Здравствуйте, gandjustas, Вы писали:
G>>>Это "чрезчур много писанины" называется визитором.
G>>>Вот и ответ на твой вопрос.
L>>Нет, визитор тут не причем.
G> G>Может все таки напишешь а там посмотрим?
Я уже написал, что в моем варианте писанины будет много. У тебя получилось компактнее. Но это не далает мое решение "визитором".
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, gandjustas, Вы писали:
G>>>>Это "чрезчур много писанины" называется визитором.
G>>>>Вот и ответ на твой вопрос.
L>>>Нет, визитор тут не причем.
G>> G>>Может все таки напишешь а там посмотрим?
L>Я уже написал, что в моем варианте писанины будет много. У тебя получилось компактнее. Но это не далает мое решение "визитором".
Здравствуйте, gandjustas, Вы писали:
L>>>>Нет, визитор тут не причем.
G>>> G>>>Может все таки напишешь а там посмотрим?
L>>Я уже написал, что в моем варианте писанины будет много. У тебя получилось компактнее. Но это не далает мое решение "визитором".
G>Ок, напиши свое решение и посмотрим.
Ты читаешь сообщения, на которые отвечаешь? Я же написал, что писанины много и писать его я не хочу.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, gandjustas, Вы писали:
L>>>>>Нет, визитор тут не причем.
G>>>> G>>>>Может все таки напишешь а там посмотрим?
L>>>Я уже написал, что в моем варианте писанины будет много. У тебя получилось компактнее. Но это не далает мое решение "визитором".
G>>Ок, напиши свое решение и посмотрим.
L>Ты читаешь сообщения, на которые отвечаешь? Я же написал, что писанины много и писать его я не хочу.
Ну тогда ты не можешь сказать какого вида получится конструкция.
А я такие конструкции писал, и уверен что у тебя будет визитор.
Здравствуйте, gandjustas, Вы писали:
G>>>Ок, напиши свое решение и посмотрим.
L>>Ты читаешь сообщения, на которые отвечаешь? Я же написал, что писанины много и писать его я не хочу.
G>Ну тогда ты не можешь сказать какого вида получится конструкция. G>А я такие конструкции писал, и уверен что у тебя будет визитор.
Будет банальный FlattenTree, уплощающий дерево в плоский список. Это типа SelectMany, но который идет не на один уровень, а вглубь.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, gandjustas, Вы писали:
G>>>>Ок, напиши свое решение и посмотрим.
L>>>Ты читаешь сообщения, на которые отвечаешь? Я же написал, что писанины много и писать его я не хочу.
G>>Ну тогда ты не можешь сказать какого вида получится конструкция. G>>А я такие конструкции писал, и уверен что у тебя будет визитор.
L>Будет банальный FlattenTree, уплощающий дерево в плоский список. Это типа SelectMany, но который идет не на один уровень, а вглубь.
А если в этом "банальном FlattenTree" изолировать сам обход от алгоритма обработки, чтобы обход дерева можно было переиспользовать, то получится визитор.
Здравствуйте, gandjustas, Вы писали:
L>>Будет банальный FlattenTree, уплощающий дерево в плоский список. Это типа SelectMany, но который идет не на один уровень, а вглубь.
G>А если в этом "банальном FlattenTree" изолировать сам обход от алгоритма обработки, чтобы обход дерева можно было переиспользовать, то получится визитор.
Не получится: алгоритм обхода и так изолирован в FlattenTree.
Единственное преимущество visitor-а — это то, что он сам будет выбирать нужный метод обработки, но в этом случае, имхо, удобнее вынести алгоритм диспетчеризации в отдельный класс. Так что никаких преимуществ у визитора в данном случае не просматривается.