Generating and serialising metadata at compile time using PostSharp - c#

I'm trying to do something which I feel should be straight forward and simple to do, yet for the life of me, I can't get it to work. Using PostSharp, I want to create an aspect that I apply to a class (or interface) definition and that aspect, at compile time, reflects the type that it has been applied to and then stores that reflection information in a variable ready for extraction at run time.
I know that the CompileTimeInitialize function should be used to generate the reflection information and save it to a variable. This all then gets serialised. However, I can't get the information stored out at run time. The RuntimeInitialize can see the variable and the data in it, but when I then get the attribute from the type elsewhere in my code using GetCustomAttributes, the attribute is empty.
Here is some of the code I have so far:
[Serializable]
[MulticastAttributeUsage(MulticastTargets.Class, AllowMultiple = false, PersistMetaData = true)]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class MetadataAttribute : TypeLevelAspect {
public MetadataAttribute() { }
private int test;
public override bool CompileTimeValidate(Type type) {
this.test = 11;
return true;
}
public override void CompileTimeInitialize(Type type, AspectInfo aspectInfo) {
this.test = 9;
}
public override void RuntimeInitialize(Type type) {
// When I break here, I can see during debugging, that test is 11 (I would have expected 9 to be honest, but I suspect that CompileTimeInitialize is not executed for a TypeLevelAspect - unless I am mistaken?)
}
}
Here is the console application that I am trying to use to extract the number:
class Program {
static void Main(string[] args) {
var ma = typeof(Test).GetCustomAttribute<MetadataAttribute>();
var test = new Test();
var ma2 = test.GetType().GetCustomAttribute<MetadataAttribute>();
// When I break here, both ma and ma2 have test set to 0.
}
}
[Metadata]
public class Test { }
Thanks in advance for any help, it is much appreciated and goes a long way to making my hair last longer on my head than in my hands :)

When you are using Type.GetCustomAttributes, you are requiring the CLR to build a new instance of custom attributes from their definition stored in metadata, i.e. by calling the constructor and setting fields and properties. Therefore, you are not getting the instance that PostSharp created and initialized, but a fully new instance.
If you want to access the PostSharp instance, you should use RuntimeInitialize to store this instance in some kind of shared repository of aspect instances, then access them from code. Note that PostSharp runs RuntimeInitialize lazily, so you won't be able to access your instance until it has been initialized.

Related

Doing a simple unit test in Visual Studio in a Windows Forms application [duplicate]

Visual Studio allows unit testing of private methods via an automatically generated accessor class. I have written a test of a private method that compiles successfully, but it fails at runtime. A fairly minimal version of the code and the test is:
//in project MyProj
class TypeA
{
private List<TypeB> myList = new List<TypeB>();
private class TypeB
{
public TypeB()
{
}
}
public TypeA()
{
}
private void MyFunc()
{
//processing of myList that changes state of instance
}
}
//in project TestMyProj
public void MyFuncTest()
{
TypeA_Accessor target = new TypeA_Accessor();
//following line is the one that throws exception
target.myList.Add(new TypeA_Accessor.TypeB());
target.MyFunc();
//check changed state of target
}
The runtime error is:
Object of type System.Collections.Generic.List`1[MyProj.TypeA.TypeA_Accessor+TypeB]' cannot be converted to type 'System.Collections.Generic.List`1[MyProj.TypeA.TypeA+TypeB]'.
According to intellisense - and hence I guess the compiler - target is of type TypeA_Accessor. But at runtime it is of type TypeA, and hence the list add fails.
Is there any way I can stop this error? Or, perhaps more likely, what other advice do other people have (I predict maybe "don't test private methods" and "don't have unit tests manipulate the state of objects").
You can use the PrivateObject class:
Class target = new Class();
PrivateObject obj = new PrivateObject(target);
var retVal = obj.Invoke("PrivateMethod");
Assert.AreEqual(expectedVal, retVal);
Note: PrivateObject and PrivateType are not available for projects targeting netcoreapp2.0 - GitHub Issue 366
“There is nothing called as standard or best practice, probably they are just popular opinions”.
Same holds true for this discussion as well.
It all depends on what you think is a unit , if you think UNIT is a class then you will only hit the public method. If you think UNIT is lines of code hitting private methods will not make you feel guilty.
If you want to invoke private methods you can use "PrivateObject" class and call the invoke method. You can watch this indepth youtube video ( http://www.youtube.com/watch?v=Vq6Gcs9LrPQ ) which shows how to use "PrivateObject" and also discusses if testing of private methods are logical or not.
Another thought here is to extend testing to "internal" classes/methods, giving more of a white-box sense of this testing. You can use InternalsVisibleTo attribute on the assembly to expose these to separate unit testing modules.
In combination with sealed class you can approach such encapsulation that test method are visible only from unittest assembly your methods. Consider that protected method in sealed class is de facto private.
[assembly: InternalsVisibleTo("MyCode.UnitTests")]
namespace MyCode.MyWatch
{
#pragma warning disable CS0628 //invalid because of InternalsVisibleTo
public sealed class MyWatch
{
Func<DateTime> _getNow = delegate () { return DateTime.Now; };
//construktor for testing purposes where you "can change DateTime.Now"
internal protected MyWatch(Func<DateTime> getNow)
{
_getNow = getNow;
}
public MyWatch()
{
}
}
}
And unit test:
namespace MyCode.UnitTests
{
[TestMethod]
public void TestminuteChanged()
{
//watch for traviling in time
DateTime baseTime = DateTime.Now;
DateTime nowforTesting = baseTime;
Func<DateTime> _getNowForTesting = delegate () { return nowforTesting; };
MyWatch myWatch= new MyWatch(_getNowForTesting );
nowforTesting = baseTime.AddMinute(1); //skip minute
//TODO check myWatch
}
[TestMethod]
public void TestStabilityOnFebruary29()
{
Func<DateTime> _getNowForTesting = delegate () { return new DateTime(2024, 2, 29); };
MyWatch myWatch= new MyWatch(_getNowForTesting );
//component does not crash in overlap year
}
}
One way to test private methods is through reflection. This applies to NUnit and XUnit, too:
MyObject objUnderTest = new MyObject();
MethodInfo methodInfo = typeof(MyObject).GetMethod("SomePrivateMethod", BindingFlags.NonPublic | BindingFlags.Instance);
object[] parameters = {"parameters here"};
methodInfo.Invoke(objUnderTest, parameters);
Ermh... Came along here with exactly the same problem: Test a simple, but pivotal private method. After reading this thread, it appears to be like "I want to drill this simple hole in this simple piece of metal, and I want to make sure the quality meets the specs", and then comes "Okay, this is not to easy. First of all, there is no proper tool to do so, but you could build a gravitational-wave observatory in your garden. Read my article at http://foobar.brigther-than-einstein.org/ First, of course, you have to attend some advanced quantum physics courses, then you need tons of ultra-cool nitrogenium, and then, of course, my book available at Amazon"...
In other words...
No, first things first.
Each and every method, may it private, internal, protected, public has to be testable. There has to be a way to implement such tests without such ado as was presented here.
Why? Exactly because of the architectural mentions done so far by some contributors. Perhaps a simple reiteration of software principles may clear up some missunderstandings.
In this case, the usual suspects are: OCP, SRP, and, as always, KIS.
But wait a minute. The idea of making everything publicly available is more of less political and a kind of an attitude. But. When it comes to code, even in then Open Source Community, this is no dogma. Instead, "hiding" something is good practice to make it easier to come familiar with a certain API. You would hide, for example, the very core calculations of your new-to-market digital thermometer building block--not to hide the maths behind the real measured curve to curious code readers, but to prevent your code from becoming dependent on some, perhaps suddenly important users who could not resist using your formerly private, internal, protected code to implement their own ideas.
What am I talking about?
private double TranslateMeasurementIntoLinear(double actualMeasurement);
It's easy to proclaim the Age of Aquarius or what is is been called nowadays, but if my piece of sensor gets from 1.0 to 2.0, the implementation of Translate... might change from a simple linear equation that is easily understandable and "re-usable" for everybody, to a pretty sophisticated calculation that uses analysis or whatever, and so I would break other's code. Why? Because they didn't understand the very priciples of software coding, not even KIS.
To make this fairy tale short: We need a simple way to test private methods--without ado.
First: Happy new year everyone!
Second: Rehearse your architect lessons.
Third: The "public" modifier is religion, not a solution.
Another option that has not been mentioned is just creating the unit test class as a child of the object that you are testing. NUnit Example:
[TestFixture]
public class UnitTests : ObjectWithPrivateMethods
{
[Test]
public void TestSomeProtectedMethod()
{
Assert.IsTrue(this.SomeProtectedMethod() == true, "Failed test, result false");
}
}
This would allow easy testing of private and protected (but not inherited private) methods, and it would allow you to keep all your tests separate from the real code so you aren't deploying test assemblies to production. Switching your private methods to protected methods would be acceptable in a lot of inherited objects, and it is a pretty simple change to make.
HOWEVER...
While this is an interesting approach to solving the problem of how to test hidden methods, I am unsure that I would advocate that this is the correct solution to the problem in all cases. It seems a little odd to be internally testing an object, and I suspect there might be some scenarios that this approach will blow up on you. (Immutable objects for example, might make some tests really hard).
While I mention this approach, I would suggest that this is more of a brainstormed suggestion than a legitimate solution. Take it with a grain of salt.
EDIT: I find it truly hilarious that people are voting this answer down, since I explicitly describe this as a bad idea. Does that mean that people are agreeing with me? I am so confused.....
From the book Working Effectively with Legacy Code:
"If we need to test a private method, we should make it public. If
making it public bothers us, in most cases, it means that our class is
doing too much and we ought to fix it."
The way to fix it, according to the author, is by creating a new class and adding the method as public.
The author explains further:
"Good design is testable, and design that isn't testable is bad."
So, within these limits, your only real option is to make the method public, either in the current or a new class.
I use this helper (object type extension)
public static TReturn CallPrivateMethod<TReturn>(
this object instance,
string methodName,
params object[] parameters)
{
Type type = instance.GetType();
BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Instance;
MethodInfo method = type.GetMethod(methodName, bindingAttr);
return (TReturn)method.Invoke(instance, parameters);
}
You can call it like this
Calculator systemUnderTest = new Calculator();
int result = systemUnderTest.CallPrivateMethod<int>("PrivateAdd",1,8);
One of the advantages is that it uses generics to pre-determine return type.
It's 2022 now!
...and we have .NET6
While this does not really answer the question, my preferred approach these days is to collocate code and test in the same C# project, with naming convention like <ClassName>.Tests.cs. Then I use internal access modifier instead of private.
In the project file, I have something like this:
<ItemGroup Condition="'$(Configuration)' == 'Release'">
<Compile Remove="**\*.Tests.cs" />
</ItemGroup>
to exclude the test files in release builds. Modify as needed.
FAQ 1: But sometimes you want to also test code in Release (optimized) build.
Answer: I find it unnecessary. I trust that the compiler will do its job without messing up my intent. So far, I've had no reason to question its ability to do so.
FAQ 2: But I really want to keep the method (or class) private.
Answer: Lots of excellent solutions in this page to try out. In my experience, having access modifier set to internal is usually more than enough since the method (or class) won't be visible outside the project it's defined. Beyond that, there's nothing more to hide.
Extract private method to another class, test on that class; read more about SRP principle (Single Responsibility Principle)
It seem that you need extract to the private method to another class; in this should be public. Instead of trying to test on the private method, you should test public method of this another class.
We has the following scenario:
Class A
+ outputFile: Stream
- _someLogic(arg1, arg2)
We need to test the logic of _someLogic; but it seem that Class A take more role than it need(violate the SRP principle); just refactor into two classes
Class A1
+ A1(logicHandler: A2) # take A2 for handle logic
+ outputFile: Stream
Class A2
+ someLogic(arg1, arg2)
In this way someLogic could be test on A2; in A1 just create some fake A2 then inject to constructor to test that A2 is called to the function named someLogic.
public static class PrivateMethodTester
{
public static object InvokePrivateMethodWithReturnType<T>(this T testObject, string methodName, Type[] methodParamTypes, object[] parameters)
{
//shows that we want the nonpublic, static, or instance methods.
var flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance;
//gets the method, but we need the methodparamtypes so that we don't accidentally get an ambiguous method with different params.
MethodInfo methodInfo = testObject.GetType().GetMethod(methodName, flags, null, methodParamTypes, null);
if (methodInfo == null)
{
throw new Exception("Unable to find method.");
}
//invokes our method on our object with the parameters.
var result = methodInfo.Invoke(testObject, parameters);
if (result is Task task)
{
//if it is a task, it won't resolve without forcing it to resolve, which means we won't get our exceptions.
task.GetAwaiter().GetResult();
}
return result;
}
}
Call it this way:
Type[] paramTypes = new Type[] { typeof(OrderTender), typeof(string) };
var parameters = new object[] { orderTender, OrderErrorReasonNames.FailedToCloneTransaction };
myClass.InvokePrivateMethodWithReturnType("myPrivateMethodName", paramTypes, parameters);
In VS 2005/2008 you can use private accessor to test private member,but this way was disappear in later version of VS
You can use nested classes to test private methods. For example (NUnit v3 is used):
internal static class A
{
// ... other code
private static Int32 Sum(Int32 a, Int32 b) => a + b;
[TestFixture]
private static class UnitTests
{
[Test]
public static void OnePlusTwoEqualsThree()
{
Assert.AreEqual(3, Sum(1, 2));
}
}
}
Furthermore tests related code can be moved to another file using 'partial class' feature, excluded from release builds using 'conditional compilation', etc. Advanced example:
File A.cs
internal static partial class A
{
// ... other code
private static Int32 Sum(Int32 a, Int32 b) => a + b;
}
File A.UnitTests.cs
#if UNIT_TESTING
partial class A
{
[TestFixture]
private static class UnitTests
{
[Test]
public static void OnePlusTwoEqualsThree()
{
Assert.AreEqual(3, Sum(1, 2));
}
}
}
#endif
I had another approach that it works for me. because I always run my tests in debug mode so I used #if DEBUG to add public before my private method. so my private method is like this:
public class Test
{
#if (DEBUG)
public
#endif
string PrivateMehtod()
{
return "PrivateMehtod called";
}
}
Sadly there is no PrivateObject class in .net6
However I wrote a small extension method capable of invoking private methods using reflection.
Have a look at the sample code:
class Test
{
private string GetStr(string x, int y) => $"Success! {x} {y}";
}
var test = new Test();
var res = test.Invoke<string>("GetStr", "testparam", 123);
Console.WriteLine(res); // "Success! testparam 123"
And here is the implementation of the extension method:
/// <summary>
/// Invokes a private/public method on an object. Useful for unit testing.
/// </summary>
/// <typeparam name="T">Specifies the method invocation result type.</typeparam>
/// <param name="obj">The object containing the method.</param>
/// <param name="methodName">Name of the method.</param>
/// <param name="parameters">Parameters to pass to the method.</param>
/// <returns>The result of the method invocation.</returns>
/// <exception cref="ArgumentException">When no such method exists on the object.</exception>
/// <exception cref="ArgumentException">When the method invocation resulted in an object of different type, as the type param T.</exception>
/// <example>
/// class Test
/// {
/// private string GetStr(string x, int y) => $"Success! {x} {y}";
/// }
///
/// var test = new Test();
/// var res = test.Invoke<string>("GetStr", "testparam", 123);
/// Console.WriteLine(res); // "Success! testparam 123"
/// </example>
public static T Invoke<T>(this object obj, string methodName, params object[] parameters)
{
var method = obj.GetType().GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (method == null)
{
throw new ArgumentException($"No private method \"{methodName}\" found in class \"{obj.GetType().Name}\"");
}
var res = method.Invoke(obj, parameters);
if (res is T)
{
return (T)res;
}
throw new ArgumentException($"Bad type parameter. Type parameter is of type \"{typeof(T).Name}\", whereas method invocation result is of type \"{res.GetType().Name}\"");
}
If PrivateObject is not available and if the class under test is not a sealed class, you can make the methods and properties you want to expose protected. Create an inherited class in the unit test file with internal methods that expose the private methods/properties under test.
If the class under test is:
class MyClass{private string GetStr(string x, int y) => $"Success! {x} {y}";}
Change it to:
class MyClass{protected string GetStr(string x, int y) => $"Success! {x} {y}";}
In your unit test file create an inherited class something like this:
class MyClassExposed: MyClass
{
internal string ExposedGetStr(string x, int y)
{
return base.GetStr(x, y);
}
}
Now you can use the inherited class MyClassExposed to test the exposed methods and properties.
.NET doesn't allow use of Accessors anymore. You can use the code I posted here for an answer to a similar question.
How do you unit test private methods?

Disable auto-generation of [Serializable] attribute by VS2015 C# compiler

VS2015 C# compiler emits [Serializable, CompilerGenerated] attributes on all auto-generated helper classes for LINQ queries. Prior versions of Visual Studio used to emit only [CompilerGenerated] attribute on such classes.
Is there a way to disable auto-generation of [Serializable] attribute in VS2015? The reason is that our obfuscator refuses to rename classes marked as [Serializable], although in our case it is 100% safe because we don't use serialization.
Here is the example of auto code generated by older compilers:
[CompilerGenerated]
private sealed class <>c
{
public static readonly Program.<>c <>9 = new Program.<>c();
// ... more stuff here
}
Here is what VS2015 emits:
[Serializable, CompilerGenerated]
private sealed class <>c
{
public static readonly Program.<>c <>9 = new Program.<>c();
// ... more stuff here
}
I want the compiler to stop generating that [Serializable] attribute. Is it possible?
I hesitated to post this... maybe i'm wrong, but i'm sure this can lead to the right direction.
So Roslyn is the compiler which generates the code (that's the default compiler in VS2015), and it's open source (see here). The LabdaRewriter.cs (here) contains the logic which rewrites the lambda into the class and does all the magic. In the GetStaticFrame method there is this line:
_lazyStaticLambdaFrame = new LambdaFrame(_topLevelMethod, scopeSyntaxOpt: null, methodId: methodId, closureId: closureId);
Now LamdaFrame is the class which represents the generated class (see here) (in your case <>c which gets the SerializableAttribute).
Remember the scopeSyntaxOpt: null part from the constructor parameter!
Here is the constructor:
internal LambdaFrame(MethodSymbol topLevelMethod, CSharpSyntaxNode scopeSyntaxOpt, DebugId methodId, DebugId closureId)
: base(MakeName(scopeSyntaxOpt, methodId, closureId), topLevelMethod)
{
_topLevelMethod = topLevelMethod;
_constructor = new LambdaFrameConstructor(this);
this.ClosureOrdinal = closureId.Ordinal;
// static lambdas technically have the class scope so the scope syntax is null
if (scopeSyntaxOpt == null)
{
_staticConstructor = new SynthesizedStaticConstructor(this);
var cacheVariableName = GeneratedNames.MakeCachedFrameInstanceFieldName();
_singletonCache = new SynthesizedLambdaCacheFieldSymbol(this, this, cacheVariableName, topLevelMethod, isReadOnly: true, isStatic: true);
}
...
}
And there is one property called IsSerializable:
// display classes for static lambdas do not have any data and can be serialized.
internal override bool IsSerializable
{
get { return (object)_singletonCache != null; }
}
As you see in the constructor this _singletonCache is basically never null when the instance is created in the GetStaticFrame method (I think this is the case where you do not capture values from the outside in you LINQ expression (FIXME)) , therefore it returns true, and I think based on this property the generated class get's the SerializableAttribute.
So I think at the moment this is hard-coded and you cannot change this, unless you touch the Roslyn source code and improve this....
I ended up writing a simple dnlib-based tool that parses compiled assembly and changes the Serialized property of every class with the [CompilerGenerated] attribute to false. Seems to work well enough for my needs.

Is it possible to access caller object from stack trace and set its property

Hi I have a possible design flaw and i need to solve it with an extension method.
Lets say I have a class and it has a property of StringCollection. Example code
public class MyProblematicClass
{
public IDbAccess Db{get;set;}
public StringCollection Errors{get;set;}
public MyProblematicClass(IDbAcces db){ Db=db;}
public int SetItem(Item i)
{
var id = Db.Save(i);
this.Errors = Db.Erros;
return id;
}
}
What I am doing is, in my unit test class I mock IDbAccess. This class validates object according to attributes. If any error occures it doesnt hit to db, it just fills its own Errors collection. For unit test I use another dbclass which just runs validation routines and here is problem i cannot get Error. Let me give you example for further understanding ( I know design is problematic, but for now I want to deal with it without changing anything)
public static class MyDbExtension
{
public static Save(Item i)
{
Validation v = new Validation();
var erros = v.ValidateObject(i);
//Here is problem i cannot pass it to MyProblematicClass
if ( errors.Count > 0 )
return -1;
else
return 1;
/* what I want to is :
var stackTrace = new StackTrace(); get stack trace
var object = stackTrace.GetFrame(1).GetMethod().GetObject() or sth like that. get object
object.GetProperties()[0].SetValue(object,errors,null); find property and set it.
*/
}
}
in my unit test :
public class UnitTest
{
Mock<IDbAccess> _db ;
MyProblematicClass _mpc;
pubic Setup()
{
_db.Setup(x=>x.Save(It.IsAny<Item>).Returns(u =>MyDbExtension.Save(u));
_mpc = new MyProblematicClass(_db.Object);
}
public void SetItem_EmptyObject_Contains3Erros()
{
Item i = new Item();
_mpc.SetItem(i);
//At this point i cannot set _mpc.Errors
}
What I want to achieve is in my DbExtension class can I access caller class and set its Errors property? I tried but it wasn unlikely yet. If anyone has any decent solution I will be appreciative and of course you can comment on design problems.
Edit
I appreciate Alex's answer he just said ignore Save method just mock Erros property and it will be ok. That make sense but what I wonder is in question, is it possible to access Stack Trace and manipulate caller methods object's property?
Thanks in advance.
You need to setup the return value of _db.Errors, something like this:
public class UnitTest
{
Mock<IDbAccess> _db ;
MyProblematicClass _mpc;
StringCollection errors;
pubic Setup()
{
_db.Setup(x=>x.Save(It.IsAny<Item>).Returns(u =>MyDbExtension.Save(u));
_db.Setup(x=>x.Errors).Returns(errors);
_mpc = new MyProblematicClass(_db.Object);
}
public void SetItem_EmptyObject_ContainsError()
{
errors.Add("Expected Error!");
Item i = new Item();
_mpc.SetItem(i);
Assert.AreEqual("Expected Error!", _mpc.Errors[0]);
}
}
I must admit I don't really follow your design, why are you using a static method for save? You could just as easily have the line:
_db.Setup(x=>x.Save(It.IsAny<Item>).Returns(-1);
Then test IDbAccess.Save() independently.
In your 'extension' class the save method has no return value, and MyProblematicClass does not inspect the return value before assigning errors.
Not sure to fully understand the question, but you cannot access the parameters on the stack from a normal program. Runtime metadata is only about static information (method, properties, constants, etc...).
I believe only a debugger (which is considered as a special beast of its own) can do this without changing the program/source, and this has serious performance cost. As a side note, here is a link that explain how to build your own managed debugger (.NET 4): CLR Managed Debugger (mdbg) Sample 4.0
Another solution is to instrument your code (automatically or using a tool) to add some tracing call that can capture the list of parameters on each traced methods. Tools like PostSharp can do this. Here is another link: Non-Invasive Tracing & Logging
You could use unmanaged debugging API to access the call stack and get the object previous function on the stack was called on.
The problem is, the stack may not contain the method you are expecting. In cases such as inlining and tail call optimization, the call stack doesn't contain the previous method called, which means you can't reliably do what you want.
For more information see this answer by Eric Lippert.
This doesn't use the call stack, but might get you some mileage:
class CalledClass
{
public static void PokeCaller()
{
Program._this.Error = "Error!!!";
}
}
class Program
{
public string Error = null;
[ThreadStatic] public static Program _this;
public void Run()
{
_this = this;
CalledClass.PokeCaller();
Console.WriteLine(Error);
Console.ReadKey();
}
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
}
Making Errors be [ThreadStatic] might be a more direct way to do it... or some other variation on that theme. You might also combine it with stack trace checking to see if you were actually called by something that has "Errors" attribute before setting it...

Controlling when the Static Constructor is called

In my custom attribute's static constructor, I search the loaded assembly for all classes decorated with my attribute and perform some action on them.
I would like the static constructor to be called as soon as possible during runtime, preferably before execution of the static void Main() entry point.
Currently it only gets called after I make some call to the attribute. I could make such a call elsewhere in my program, but ideally the attribute's functionality would be self-contained.
Looking for answers, I read this on MSDN:
The user has no control on when the static constructor is executed in the program.
But surely there is some tricky, sly, or mischievous workaround to get a static constructor to be called ASAP. Perhaps an attribute, reflection, or some other kind of magic could be used. Can it be done?
Because people would undoubtedly tell me that there is no good reason to do what I ask, I present my purpose and my code: I am trying to use attributes to declaratively configure a db4o factory. If my attribute's static constructor is called after I've already established a connection, then it has no effect and is useless. Therefore it must be called before my program gets a chance to establish such a connection.
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
sealed public class CascadeOnUpdateAttribute : Attribute
{
public bool Flag { get; private set; }
public CascadeOnUpdateAttribute() : this(true) { }
public CascadeOnUpdateAttribute(bool flag)
{
Flag = flag;
}
static CascadeOnUpdateAttribute()
{
var targets = from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
from attribute in type.GetCustomAttributes(typeof(CascadeOnUpdateAttribute), false).Cast<CascadeOnUpdateAttribute>()
select new { Type = type, Cascade = attribute.Flag };
foreach (var target in targets)
{
Db4oFactory.Configure().ObjectClass(target.Type).CascadeOnUpdate(target.Cascade);
}
}
}
Update:
I ended up using an abstract attribute with a static method. This way I can derive as many attributes as I like and they will all be applied to a specified config by calling this one method.
public abstract class Db4oAttribute : Attribute
{
public abstract void Configure(IConfiguration config, Type type);
public static void ApplyAttributes(IConfiguration config)
{
var targets = from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
from attribute in type.GetCustomAttributes(typeof(Db4oAttribute), false).Cast<Db4oAttribute>()
select new { Type = type, Attribute = attribute };
foreach (var target in targets)
{
target.Attribute.Configure(config, target.Type);
}
}
}
And the call site:
Db4oAttribute.ApplyAttributes(Db4oFactory.Configure());
_db = Db4oFactory.OpenFile("Test.db4o");
As Marc says, I would do it explicitly in Main if I were you.
You can invoke the type initializer for a type explicitly using the Type.TypeInitializer property and invoking it. However, this will cause it to run again even if it's already been run which could produce unexpected results.
I would personally move that code out of the static initializer completely. It's configuration code - why not just make it a static method which you can call explicitly? I'm not even sure I'd have it in the attribute class itself, but at least explicitly calling:
CascadeOnUpdateAttribute.ConfigureDb4oFactories();
is clearer than calling a dummy method or forcing type initialization some other way, just to get a side effect.
If you want the static constructor to get called, then add a dummy method to the type and simply call it at the start of your code (Main etc); if it is a trivial / empty method you might want to mark it for no inlining etc.
class SomeType {
static SomeType() {
Console.WriteLine("SomeType.cctor");
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void Init() { }
}
static class Program {
static void Main() {
SomeType.Init();
Console.WriteLine("hi");
}
}
You can use reflection to call the static constructor, but I don't recommend it; if you use reflection you can actually call the .cctor multiple times, and that is never a good thing...
You can avoid the static dummy method by calling
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(CascadeOnUpdateAttribute).TypeHandle)
I think the use of the static constructor smells; I would consider refactoring your code to control access to the db4o factory so that you don't need to use it.

Can I change a private readonly field in C# using reflection?

I am wondering, since a lot of things can be done using reflection, can I change a private readonly field after the constructor completed its execution?
(note: just curiosity)
public class Foo
{
private readonly int bar;
public Foo(int num)
{
bar = num;
}
public int GetBar()
{
return bar;
}
}
Foo foo = new Foo(123);
Console.WriteLine(foo.GetBar()); // display 123
// reflection code here...
Console.WriteLine(foo.GetBar()); // display 456
You can:
typeof(Foo)
.GetField("bar",BindingFlags.Instance|BindingFlags.NonPublic)
.SetValue(foo,567);
The obvious thing is to try it:
using System;
using System.Reflection;
public class Test
{
private readonly string foo = "Foo";
public static void Main()
{
Test test = new Test();
FieldInfo field = typeof(Test).GetField
("foo", BindingFlags.Instance | BindingFlags.NonPublic);
field.SetValue(test, "Hello");
Console.WriteLine(test.foo);
}
}
This works fine. (Java has different rules, interestingly - you have to explicitly set the Field to be accessible, and it will only work for instance fields anyway.)
I agree with the other answers in that it works generally and especially with the comment by E. Lippert that this is not documented behavior and therefore not future-proof code.
However, we also noticed another issue. If you're running your code in an environment with restricted permissions you might get an exception.
We've just had a case where our code worked fine on our machines, but we received a VerificationException when the code ran in a restricted environment. The culprit was a reflection call to the setter of a readonly field. It worked when we removed the readonly restriction of that field.
You asked why you would want to break the encapsulation like that.
I use an entity helper class to hydrate entities. This uses reflection to get all the properties of a new empty entity, and matches the property/field name to the column in the resultset, and set's it using propertyinfo.setvalue().
I don't want anyone else to be able to change the value, but I don't want to take all the effort to custom code hydration methods for every entity either.
My many of my stored procs return resultsets that don't correspond directly to tables or views, so the code gen ORM's do nothing for me.
Don't do this.
I just spent a day fixing a surreal bug where objects could be not of their own declared type.
Modifying the readonly field worked once. But if you tried to modify it again, you'd get situations like this:
SoundDef mySound = Reflection_Modified_Readonly_SoundDef_Field;
if( !(mySound is SoundDef) )
Log("Welcome to impossible-land!"); //This would run
So don't do it.
This was on the Mono runtime (Unity game engine).
Another simple way to do this using unsafe (or you could pass the field to a C method via DLLImport and set it there).
using System;
namespace TestReadOnly
{
class Program
{
private readonly int i;
public Program()
{
i = 66;
}
private unsafe void ForceSet()
{
fixed (int* ptr = &i) *ptr = 123;
}
static void Main(string[] args)
{
var program = new Program();
Console.WriteLine("Contructed Value: " + program.i);
program.ForceSet();
Console.WriteLine("Forced Value: " + program.i);
}
}
}
The answer is yes, but more importantly:
Why would you want to? Intentionally breaking encapsulation seems like a horrifically bad idea to me.
Using reflection to change a readonly or constant field is like combining the Law of Unintended Consequences with Murphy's Law.
I just want to add that if you need to do this stuff for unit testing, then you can use:
A) The PrivateObject class
B) You will still need a PrivateObject instance, but you can generate "Accessor" objects with Visual Studio. How to: Regenerate Private Accessors
If you are setting private fields of an object in your code outside of unit testing, that would be an instance of "code smell" I think that perhaps the only other reason you would want to do this is if you are dealing with a third party library and you can't change the target class code. Even then, you probably want to contact the 3rd party, explain your situation and see if they won't go ahead and change their code to accomodate your need.

Categories

Resources