Add PostSharp Aspect to System.IO namespace? - postsharp

I am looking to add my aspect to the system.io namespace, I already searches lots of solutions which didn't do the trick but basically I want to handle exceptions and do some logging on the File class from System.IO namespace. Just like adding [MyAspect] to the top of the class..
Is there a way?

Let's consider aspect like this:
[PSerializable]
public class MyAspect : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
}
}
You can apply this aspect to any 3rd assembly called from your project by applying MyAspect:
[assembly: MyAspect(AttributeTargetAssemblies = "mscorlib", AttributeTargetTypes = "System.IO.*")]
When you specify this assembly attribute then PostSharp decorates all calls from your project to methods from System.IO namespace in mscorlib assembly with MyAspect.

Related

Can I #define a constant solutionwide within c# code without project settings?

I know this was aksed and answered a a couple of times e.g.
Solution-wide #define, Is There anyway to #define Constant on a Solution Basis? and How to define a constant globally in C# (like DEBUG).
But in my case I can not use any of the suggested methods:
I'm writing on different "modules" (or plugins if you want so) for UnityProjects (kind of a package providing a certain functionality). The idea is that a developer can load a certain "module" to use in his project by importing a UnityPackage with all scripts and resources in it.
But some of these modules themselves depend on other modules. So what I tried so far was having a class Constants in each module with seperated namespaces and preprocessor definitions.
Module A
#if !MODULE_A
#define MODULE_A // BUT I WOULD NEED THIS GLOBAL NOT ONLY HERE
#endif
namespace Module_A
{
public static class Constants
{
// some constants for this namespace here
}
}
Module B
#if !MODULE_B
#define MODULE_B // BUT I WOULD NEED THIS GLOBAL NOT ONLY HERE
#endif
#if !MODULE_A // WILL BE NOT DEFINED OFCOURSE SINCE #define IS NOT GLOBAL
#error Module A missing!
#else
namespace Module_B
{
public static class Constants
{
// some constants for this namespace here
}
// and other code that might require Module A
}
#endif
But ofcourse this cannot work like this since #defines are not global but only in the current file.
Problem
For this whole idea of modules and a simple "load your modules" I can not ask the user to first make changes to the project or solution settings how e.g. suggested by this answer but instead have to use only the (c#) resources that come imported with the UnityPackage (at least with my current know-how).
Is there any way to somehow set/define those constants for the entire Unity-Project by only importing the module's UnityPackage?
Edit:
I could find a solution for 1 definition in Unity using Assets/msc.rsp. But this still wouldn't work for multiple modules since they would have to write into the same file.
After a lot of searches I've finally been able to put together a surprisingly simple solution I'ld like to share with you:
InitializeOnLoad
Unity has an attribute [InitializeOnLoad]. It tells Unity to initialize according class as soon as
Unity is launched
After any re-compiling of scripts => also after importing a new unitypackage with scripts
static Constructor
In their Running Editor Code On Launch example, they show, how to combine this with a static constructor.
From static-constructors:
A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced.
While usually you still would have to create an instance of the class, the static constructor is "instanciated/executed" instantly when the class is initliazed, which we force using the [InitializeOnLoad] attribute.
Scripting Define Symbols
Further Unity actually has project wide defines in the PlayerSettings.
And the good part is: We also have access to them via scripting API:
PlayerSettings.GetScriptingDefineSymbolsForGroup
PlayerSettings.SetScriptingDefineSymbolsForGroup.
So what I did now is the following
Module A
This module has no dependencies but just defines a "global define" in the PlayerSettings. I placed this script somewhere e.g. in Assets/ModuleA/Editor (important is the last folder's name).
using System.Linq;
using UnityEditor;
namespace ModuleA
{
// Will be initialized on load or recompiling
[InitializeOnLoad]
public static class Startup
{
// static constructor is called as soon as class is initialized
static Startup()
{
#region Add Compiler Define
// Get the current defines
// returns a string like "DEFINE_1;DEFINE_2;DEFINE_3"
var defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
// split into list just to check if my define is already there
var define = defines.Split(';').ToList();
if (!define.Contains("MODULE_A")
{
// if not there already add my define
defines += ";MODULE_A";
}
// and write back the new defines
PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, defines);
#endregion
}
}
}
Module B
This module depends on Module A. So itself defines a "global define" (so later Modules can check their dependecies on Module B) but additionally it checks first, if Module A is imported. If Module A is missing, it prints an error to the Debug Console.
(You could as well throw a compiler error using #error SOME TEXT, but for some reason this is not capable of printing out the URL correctly so I decided for the Debug.LogError)
I placed this script somewhere e.g. in Assets/ModuleB/Editor
#if MODULE_A
using System.Linq;
#endif
using UnityEditor;
#if !MODULE_A
using UnityEngine;
#endif
namespace ModuleB
{
// Will be initialized on load or recompiling
[InitializeOnLoad]
public static class Startup
{
// static constructor is called as soon as class is initialized
static Startup()
{
#if !MODULE_A
Debug.LogErrorFormat("! Missing Module Dependency !" +
"\nThe module {0} depends on the module {1}." +
"\n\nDownload it from {2} \n",
"MODULE_B",
"MODULE_A",
"https://Some.page.where./to.find.it/MyModules/ModuleA.unitypackage"
);
#else
// Add Compiler Define
var defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
var define = defines.Split(';').ToList();
if (!define.Contains("MODULE_B"))
{
defines += ";MODULE_B";
}
PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, defines);
#endif
}
}
}
So later in other scripts of Module B I have two options (both do basically the same)
I can either check everywhere #if MODULE_A to check exactly the module this script relies on
or I can instead check #if MODULE_B to rather check with one line if all dependecies are fulfilled since otherwise I don't define MODULE_B.
On this way I can completely check all dependencies between certain modules which is awesome. The only two flaws I saw until now are:
We have to know how the define (e.g. MODULE_A) looks like for every module and if it is changed in the future it has to be changed in all depending modules as well
The "global define" isn't getting removed in case the module is deleted from the project
But well - which solution is perfect?
In general, the way I would solve this problem in C# is by defining a common set of interfaces that all your modules would contain. I think you can do this with Unity by placing the files from each module in the same location, thus allowing later installations to overwrite those same files (with, obviously, the same content). You would then put editor controls that expose properties to hold instances of those interfaces and then wire them up in the UI. You would test those properties for a value of null to determine which ones are missing.
Common.cs:
public interface IModuleA {}
public interface IModuleB {}
ModuleA.cs
public class ModuleA : IModuleA {}
ModuleB.cs
public class ModuleB : IModuleB
{
public IModuleA ModuleAInstance {get; set;}
private bool IsModuleAPresent()
{
return !ModuleAInstance == null;
}
}
The ideal way to solve it would be with a package manager and proper dependency injection, but doing that with Unity is not straightforward.

PostSharp AOP - Unable to apply aspect to mscorlib System.IO.StreamReader members

**I'm using PostSharp Express... not sure that would make a difference in this instance though.
I've got an OnMethodBoundary->OnEntry aspect that successfully multicasts at the assembly level to class members in my own code, but when I attempt to apply it to mscorlib System.IO.StreamReader members, no dice. Based on the searching I've done on the PostSharp web site, here on SO, and on Google, I can't tell what the correct way to go about this is with the current version of PostSharp. Does anyone know? Hopefully I'm just missing something simple :\
Here's the aspect followed by multicast attribute I'm using:
namespace Test.Aspects {
[AttributeUsage(AttributeTargets.Assembly)]
[MulticastAttributeUsage(MulticastTargets.Method, AllowMultiple = false)]
[Serializable]
public class PatchStreamReaderAttribute : OnMethodBoundaryAspect {
public override void OnEntry(MethodExecutionArgs args) {
System.Threading.Thread.Sleep(1000);
}
}
}
[assembly: PatchStreamReader(AttributeTargetMembers = "ReadLine", AttributeTargetAssemblies = "mscorlib", AttributeTargetTypes = "System.IO.StreamReader")]
Usually, when you apply an aspect in a given assembly, PostSharp will modify that assembly during its build process. This, of course, cannot happen for mscorlib or, in fact, for any 3-rd party library you reference but do not build from source code.
This is why PostSharp uses different approach when applying aspects to the referenced assemblies using AttributeTargetAssemblies. Instead of modifying the target 3-rd party assembly, PostSharp will modify the calls from your assembly to the target assembly.
This, of course, gives you less options of where you can inject your code. For example, PostSharp can detect the call to the library's method and inject the aspect around that call. But you cannot inject the aspect around the static or instance constructor of the type from the library.
You also need to pay attention to the AttributeTargetTypes property when applying the aspect. For example, you want to apply the aspect on the calls to the StreamReader.ReadLine() method. This virtual ReadLine() method is originally declared on the TextReader class and StreamReader overrides the method. If you look at the IL, then the method call looks like this:
callvirt instance string [mscorlib]System.IO.TextReader::ReadLine()
This means you need to set AttributeTargetTypes property to "System.IO.TextReader" to apply the aspect to the ReadLine() method.

Add new Constructor to an existing Java Class via AspectJ

Trying to clean up some nasty code, for which we dont have the source code. Imagine something like this:
public class Driver{
private String paramA;
private String paramB;
new Driver(HugeAndOverbloatedObject object)
{
paramA = object.getSubObject4711().getParamX();
paramB = object.getSubObject4712().getParamY();
}
}
This third library has this all over the place: tight coupling via constructors, eventhough the classes are hardly related. The rude combination of private members and forced constructor inheritance make the extension of the code virtually impossible without creating "sloppy" constructor parameter objects.
So I am trying to manipulate the classes via AspectJ and compile time weaving, so I can slim down on the constructors, to something like this:
Driver driver = new Driver("paramA", "paramB");
I think this should be possible, and I have made some progress. If I have something like this:
public aspect NewConstructor {
Driver.new(String parameterA, String parameterB){
//New Constructor Code
}
}
and run this through the weaver I actually find a new constructor in the driver, but not quite as I expected.
Issue: Unexpected third Parameter in the woven class
I was hoping I can invoke it with two parameters:
new Driver("paramA", "paramB")
Instead I need to invoke it with three parameters:
new Driver("paramA", "paramB", new NewConstructor())
Why do I need to instantiate a new instance of the aspect and pass it as an argument? Can this be prevented?
Something odd is going on here. You should not need to add the aspect as a third argument to the constructor. In fact, when I try this myself using the following class and aspect, I do not get any compile errors:
Java class:
package pack;
public class Driver {
public static void main(String[] args) {
new Driver("paramA", "paramB");
}
}
Aspect:
package pack;
public aspect NewConstructor {
public pack.Driver.new(String parameterA, String parameterB){
}
}
Are your Java class and aspect in different projects? Are you using an aspect path and/or in path? Are you using load time weaving?
If after doing a full build of your project you still see the probem, it's worth raising a bug for AspectJ.

Loading custom static classes in PowerShell

I've searched and searched for info on how to load a custom static class in PowerShell but up to now no avail. I'm googled out. I've seen enougth info and samples on how to load custom classes that need to be instantiated or how to load .Net framework classes but not exactly what I'm looking for.
I'm trying to use a custom dll, written in C# with following structure:
namespace Custom.NameSpace
{
public static class AppCfgHelper
{
public static XmlNode SomeXmlNodeFunction( XmlNode xmlRoot )
{
...
}
}
}
Can anybody help please?
There are two steps. First load the assembly containing your static class e.g.:
Add-Type -Path <path-to-dll>
Then use invoke the static method using PowerShell's static method syntax [typename]::membername e.g.:
$returnedNode = [Custom.NameSpace.AppCfgHelper]::SomeXmlNodeFunction($rootNode)

JAXB compile error, unused parameters for afterUnmarshall

I'm using void afterUnmarshal(Unmarshaller unmarshaller, Object parent) in my beans and have got the complier set to fail if parameters are not used.
The compiler seems to be okay with unused parameters if I override a superclass/interface that has a javadoc for the param.
But I can't find any class to override the afterUnmarshall method. Is there no unmarshaller interface or something like it to solve this problem?
There is not interface provided with the JAXB APIs. We designed it this way so that you could add just one of afterUnmarsal or beforeUnmarshal if you wanted. You could solve this issue by introducing your own interface:
package com.example;
public interface UnmarshallerListener {
void afterUnmarshal(Unmarshaller unmarshaller, Object parent);
}