Примечание. Этот вопрос был обновлен новой информацией.Пожалуйста, смотрите нижнюю половину этого текста.(Оригинальный вопрос оставлен здесь для контекста.)
Можно ли как-то определить свой атрибут, чтобы, если он определен в методе, который переопределен, атрибут все еще применяется?
Причина, по которой я спрашиваю, состоит в том, что у меня есть атрибут, который вводит некоторое поведение в метод, но поведение не применяется, когда метод вызывается, как в любом из случаев в дочернем классе, и я хотел бы, чтобы он был,
class BaseClass
{
[MyThing]
virtual void SomeMethod()
{
// Do something fancy because of the attribute.
}
}
class ChildClass
{
override void SomeMethod()
{
// Fancy stuff does happen here too...
base.SomeMethod();
}
void AnotherMethod()
{
// ...but not here. And I'd like it to =(
base.SomeMethod();
}
}
Атрибут определен следующим образом:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MyThingAttribute : Attribute
Текущий код для поиска методов с атрибутом следующий:
var implementation = typeof(TheTypeWereCurrentlyInvestigating);
var allMethods = (from m in implementation.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)
let attribs = (TransactionAttribute[]) m.GetCustomAttributes(typeof (TransactionAttribute), true)
where attribs.Length > 0
select Tuple.Create(m, attribs.Length > 0 ? attribs[0] : null)).ToList();
Я не сделал 'Я не могу написать эту часть, и я не могу сказать, что я на 100% от того, что делает каждая ее часть ... Но сейчас мы можем предположить, что я контролирую весь задействованный код.(Это проект с открытым исходным кодом, так что я могу, по крайней мере, создать свою собственную версию и представить патч владельцам проекта ...)
У меня есть пара других случаев тоже - в основном, я хочу иметь такое поведениевводится всякий раз, когда я вызываю метод в базовом классе, независимо от того, каким путем я туда попал - но если я решу этот метод, у меня могут появиться идеи о том, как заставить других работать.Если нет, я вернусь с ними.
ОБНОВЛЕНИЕ:
ОК, поэтому я сел с проектом Castle.Transactions и создал несколько очень простых тестов, чтобы увидеть, что работаета что нет.Оказывается, мои первоначальные предположения о том, что работает, а что нет, не совсем совпадают.
Что я сделал:
Я создал тестовый класс, в котором есть один метод, украшенныйатрибут и который вызывает метод Assert
, который проверяет, что поведение было введено правильно (то есть, что есть транзакция).Затем я создал пару классов, которые наследуют этот тестовый класс, чтобы увидеть, в каких случаях все работает так, как я ожидаю.
Что я нашел:
Вызывая метод тестанепосредственно в тестовом классе и из различных методов дочерних классов я обнаружил следующее о том, что работает, а что нет:
Method called Access modifiers Does it work?
************* **************** *************
SomeMethod() on base class* N/A Yes
OtherMethod() on child neither NO <-- headache!
OtherMethod() on child hiding (new) No
SomeMethod() on child hiding (new) No
OtherMethod() on child overrides No
OtherMethod() on child* overrides Yes
SomeMethod() on child overrides Yes
Во всех случаях, кроме одного, отмеченного *
, base.SomeMethod()
был вызван из метода, примененного в тесте.В первом случае был вызван тот же метод, но непосредственно из теста, поскольку дочерний класс не задействован.Во втором случае (из отмеченных *
) был вызван метод переопределения, то есть this.SomeMethod()
, так что это действительно эквивалентно последнему случаю.Я не использую никаких избыточных квалификаторов, поэтому в этом методе вызов просто SomeMethod()
.
Что я хочу:
Это случай с пометкой "головная боль", что я действительнохочу решить;как внедрить поведение в базовый класс, хотя я вызываю его из своего дочернего класса.
Причина, по которой мне нужен этот конкретный случай, заключается в том, что я использую этот шаблон в хранилище, где базовый класс определяет метод Save(T entity)
, украшенный атрибутом Transaction
.В настоящее время я должен переопределить этот метод, просто чтобы получить оркестровку транзакции, что делает невозможным изменение типа возвращаемого значения;в базовом классе это void
, но в моей реализации я бы хотел сделать его Error<T>
.Это невозможно при переопределении, и, поскольку я не могу решить проблему, назвав метод по-другому, я в растерянности.