I have a method like this
public void MyMethod(MyType parameter) { /* ... */ }
I'd like to force a value into one of parameter's public property before the method gets excecuted.
It must happen before method excecution because some postSharp OnMethodBoundaryAspect.OnEntry depends on this property's value.
An ideal solution could looks like this:
[SetPropertyBeforeEntry(0 /* Argument's index*/, nameof(MyType.MyProperty) /* Property to set */, 1234 /* Value */)]
public void MyMethod(MyType parameter) { /* ... */ }
You have two options - OnMethodBoundaryAspect and MethodInterceptionAspect, but in both cases you need to use aspect dependencies to make sure you have proper order (PostSharp would produce warnings if the order is not specified).
PostSharp provides various ways to specify dependencies between aspects. You can find more here.
The following demonstrates changing of the parameter's property before (without the specific logic for argument type, property or index.
class Program
{
static void Main(string[] args)
{
new TestClass().Foo(new TestData());
}
}
public class TestClass
{
[ObservingAspect]
[ArgumentChangingAspect]
public int Foo(TestData data)
{
Console.WriteLine("Method observed: {0}", data.Property);
return data.Property;
}
}
public class TestData
{
public int Property { get; set; }
}
[AspectTypeDependency(AspectDependencyAction.Order, AspectDependencyPosition.Before, typeof(ObservingAspect))]
[PSerializable]
public class ArgumentChangingAspect : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
((TestData) args.Arguments[0]).Property = 42;
}
}
[PSerializable]
public class ObservingAspect : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
Console.WriteLine("Aspect observed: {0}", ((TestData)args.Arguments[0]).Property);
}
}
Related
I understand how Auto-Implemented Properties work and how they are supposed to help. I was wondering if I could still use it somehow in a more advanced way.
Imagine I have this:
public int SomeProperty { get; set; }
Which is basically another way of writing the code below (but using Automatic Properties).
private int _someField;
public int SomeProperty
{
get { return _someField;}
set { _someField = value;}
}
What I want to do is write:
private int _someField;
public int SomeProperty
{
get { return _someField;}
set { FunctionA(); _someField = value;}
}
But using the advantages of the Auto-Implemented Properties. Is that possible?
I tried something like this:
public int SomeProperty { get; set{FunctionA();} }
But it doesn't work. Thank you everybody for the help, I know it's silly but I am curious about it.
No, it is not allowed. See the language spec:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#properties
An automatically implemented property (or auto-property for short), is a non-abstract non-extern property with semicolon-only accessor bodies.
I didn't find free tool, but PostSharp handles this. It has trial period and some free-to-use options. Anyway take a look at method decoration and AOP frameworks.
using System;
using PostSharp.Aspects;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
var someClass = new SomeClass();
Console.WriteLine($"{nameof(someClass.Value)} = {someClass.Value}");
someClass.Value = 42;
Console.WriteLine($"{nameof(someClass.Value)} = {someClass.Value}");
}
}
class SomeClass
{
public int Value { get; [Decorate] set; }
private void SomeFunction()
{
Console.WriteLine("SomeFunction called");
}
[Serializable, AttributeUsage(AttributeTargets.Method)]
public class DecorateAttribute : MethodInterceptionAspect
{
public override void OnInvoke(MethodInterceptionArgs args)
{
var target = (SomeClass)args.Instance;
target.SomeFunction();
args.Proceed(); // performs the method it applied to
}
}
}
}
Output:
Value = 0
SomeFunction called
Value = 42
How can I get the type (not a name string, but a type itself) of the current class, in a static method of an abstract class?
using System.Reflection; // I'll need it, right?
public abstract class AbstractClass {
private static void Method() {
// I want to get CurrentClass type here
}
}
public class CurrentClass : AbstractClass {
public void DoStuff() {
Method(); // Here I'm calling it
}
}
This question is very similar to this one:
How to get the current class name at runtime?
However, I want to get this information from inside the static method.
public abstract class AbstractClass
{
protected static void Method<T>() where T : AbstractClass
{
Type t = typeof (T);
}
}
public class CurrentClass : AbstractClass
{
public void DoStuff()
{
Method<CurrentClass>(); // Here I'm calling it
}
}
You can gain access to the derived type from the static method simply by passing the type as a generic type argument to the base class.
I think you will have to either pass it in like the other suggestion or create a stack frame, I believe if you put an entire stack trace together though it can be expensive.
See http://msdn.microsoft.com/en-us/library/system.diagnostics.stacktrace.aspx
if you are calling this static method only from derived classes you can use 'System.Diagnostics.StackTrace' like
abstract class A
{
public abstract string F();
protected static string S()
{
var st = new StackTrace();
// this is what you are asking for
var callingType = st.GetFrame(1).GetMethod().DeclaringType;
return callingType.Name;
}
}
class B : A
{
public override string F()
{
return S(); // returns "B"
}
}
class C : A
{
public override string F()
{
return S(); // returns "C"
}
}
The method can't be static if you're going to call it without passing in a type. You can do this:
public abstract class AbstractClass {
protected void Method() {
var t = GetType(); // it's CurrentClass
}
}
If you also need it to be accessible from a static context, you can add an overload, even a generic overload, e.g.:
public abstract class AbstractClass {
protected static void Method<T>() {
Method(typeof(T));
}
protected static void Method(Type t) {
// put your logic here
}
protected void Method() {
Method(GetType());
}
}
Suppose you had such code:
public Base
{
abstract void Register();
}
public Registrator1: Base
{
override void Register()
{
//uses the current state of the object to populate the UI captions
}
}
public Registrator2: Base
{
override void Register()
{
//uses the current state of the object to populate the UI captions
}
}
But When you receive a new business rule asking you to write Registrator3 which actually registers based on some parameter and you change your code base to the next:
public Base
{
abstract void Register(externalParam);
}
public Registrator1: Base
{
override void Register(externalParam)
{
//uses the current state of the object to populate theUI
}
}
public Registrator2: Base
{
override void Register(externalParam)
{
//uses the current state of the object to populate the UI
}
}
public Registrator3: Base
{
override void Register(externalParam)
{
//uses a DDD - service passed in the params to populate the UI
}
}
But Registrator1 and Registrator2 do not need that param and the code becomes smelly. What are the ways to re-write this code?
You could use an object as a parameter here; which is commonly used in scenarios where the number of parameters can vary depending on the call being used.
struct RegistrationInfo
{
public static readonly RegistrationInfo Empty = new RegistrationInfo();
public string Username;
public string CustomerName;
public string Validity;
}
abstract class Base
{
public abstract void Register(RegistrationInfo info);
// If you want to retain the paramaterless call:
public void Register()
{
Register(RegistrationInfo.Empty);
}
}
class Registrar1 : Base
{
public override void Register(RegistrationInfo info)
{
if (info.Username == null) throw new ArgumentNullException("info.Username");
}
}
class Registrar2 : Base
{
public override void Register(RegistrationInfo info)
{
if (info.CustomerName == null) throw new ArgumentNullException("info.CustomerName");
}
}
This has the advantage that you don't need to change method parameters (which is breaking interface) each time a parameter is added. The usage also becomes somewhat self-documenting:
var r = new Registrar1();
r.Register(new RegistrationInfo(){ Username = "JimJoe" });
r.Register(RegistrationInfo.Empty);
It's like air freshener for this type of code smell, while it's still smelly; you can make it smell nicer.
Finally you can make the call-site cleaner by making it a params argument (this has a small amount of overhead); in all honesty though it is more smelly because it's a language hack. Finally you could improve it with generics:
class RegistrationInfo
{
}
class RegistrationInfo1 : RegistrationInfo
{
public string Arg;
}
class RegistrationInfo2 : RegistrationInfo
{
public int Arg;
}
interface IBase<in TRegistration>
where TRegistration : RegistrationInfo
{
void Register(TRegistration registration);
}
class Base : IBase<RegistrationInfo>
{
public void Register(RegistrationInfo registration)
{
}
}
class Registrar1 : IBase<RegistrationInfo1>
{
public void Register(RegistrationInfo1 arg)
{
}
}
class Registrar2 : IBase<RegistrationInfo2>
{
public void Register(RegistrationInfo2 arg)
{
}
}
Is it not possible to contain the logic for externalParam in Registrator3?
In other words, Registrator3 uses the param, then calls the unmodified parameterless base?
A lot really depends on where the logic belongs. If it is something intrinsic to the base, then put it in the base, and either overload the Register() function or supply a default value for the param so that sub classes don't need to provide it.
Assuming you want to reuse the registration logic from the base class, you could update the code as follows:
public class Base
{
public virtual void Register(object externalParam)
{
// base registration logic goes here
}
}
public class Registrator1: Base
{
public override void Register(object externalParam)
{
base.Register(null);
// custom registration logic goes here
}
}
public class Registrator2: Base
{
public override void Register(object externalParam)
{
base.Register(null);
// custom registration logic goes here
}
}
public class Registrator3: Base
{
public override void Register(object externalParam)
{
base.Register(externalParam);
// custom registration logic goes here
}
}
HTH,
Cosmin
EDIT: Updated code to compile.
I am running a .NET 4.0 Web Application (not web site) and PostSharp 1.5. I cannot get the OnEntry override method to execute using the OnMethodBoundaryAspect base class. Here is some relevant code:
public sealed class MonitorAttribute : OnMethodBoundaryAspect {
public string[] SomeValue { get; protected set; }
public MonitorAttribute (params string[] someValue){
SomeValue = someValue;
}
public override void OnEntry(MethodExecutionEventArgs eventArgs){
// do Something here
base.OnEntry(eventArgs);
}
}
public sealed class MyUsageClass : IMyUsageClass {
[Monitor(new string[]{ 'Test' })
public void SomeMethod {
// Do something else in here
}
}
Am I missing something? It never hits the OnEntry method. I also tried replacing my PostSharp.dll and PostSharp.Laos.dll dependencies with the new 2.0 version. If it makes any difference MyUsageClass is instantiated by StructureMap.
Yes, every dev will need to have PostSharp installed. If you're just using the starter edition then it's all free.
Posting this as an answer to show you the code. My test code
class Program
{
[Monitor]
static void Main(string[] args)
{
}
}
[Serializable]
public class MonitorAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
Console.WriteLine("OnEntry");
}
}
The code after compilation
internal class Program
{
[CompilerGenerated, DebuggerNonUserCode]
internal sealed class <>z__Aspects
{
internal static MethodBase m1 = MethodBase.GetMethodFromHandle(ldtoken(Main()));
internal static readonly MonitorAttribute a0 = (MonitorAttribute)<>z__AspectsImplementationDetails.aspects1[0];
}
private static void Main(string[] args)
{
Program.<>z__Aspects.a0.OnEntry(null);
}
}
I only want this invoked when a property is set. Why is this not working?
[DirtyTrackingAttribute(AttributeTargetElements =
PostSharp.Extensibility.MulticastTargets.Property)]
class Program
{
public static string Test { get; set; }
static void Main(string[] args)
{
TestIt();
Test = "foo";
Console.ReadKey();
}
private static void TestIt()
{
Console.WriteLine("Real method called");
}
}
[Serializable]
public class DirtyTrackingAttribute : OnMethodInvocationAspect
{
public override void OnInvocation(MethodInvocationEventArgs eventArgs)
{
Console.WriteLine("Property invoked");
eventArgs.Proceed();
}
}
If you want the aspect to be applied on property setters only, you can filter the method name with the expression "set_*":
[DirtyTrackingAttribute(AttributeTargetMembers="set_*")]
PostSharp 1.* does not support explicitely properties; property accessors are considered as plain methods.