I have a project where I do this:
public class Stuff
{
[ExecuteOnComputer("192.168.1.2")]
public void methodA()
{
return "ok";
}
[ExecuteOnComputer("192.168.1.3")]
public void methodB()
{
return methodA();
}
}
I use the ExecuteOnComputer attribute in an Executor class that dispatches the call to the computer located at the IP address specified in the attribute. (this is not the exact thing I am doing but is similar enough for the purpose of simplifying the question).
Now, I want to ensure that if a method tagged with the ExecuteOnComputer calls another method tagged with the ExecuteOnComputer attribute, then something alerts me if the 2 attributes have a different IP address (the example above should alert me somehow that the attributes are not well defined).
Obviously, the C# syntax is correct, and it's impossible to use reflection on the produced DLL, because reflection can't tell me that methodB calls methodA.
So I am thinking that a way to do this would be to have an extension in Visual Studio check that for me during editing or compile time. I need some Roslyn code to analyze the call tree from methodB.
There seems to be some solutions out there, but the docs are not great. I was hoping there would be something available with some Roslyn/VS extension boilerplate code already done.
Can anyone help me with this?
Related
I plan to give method calling privileges to certain classes in my program using Attributes but I just have no clude how to.
For example, here is what I want my Customer class to look like:
[ForbiddenMethodsAttr(listOfMyForbiddenMethods)]
public class Customer
{
public Customer { }
}
And if I want to call a given function, the intellisense should warm me that I can't, The reason I want to do this is because calling those functions may cause some issues and not I'm the only one who will code this project but some friends as well. So if it is possible to write such an attribute, how to do it?
You could mark the methods as obsolete and then anyone calling them will get a compiler warning (though not error). Its not elegant, but neither is attempting to restrict method calls without using scoping conventions.
I've founded the OnMethodBoundaryAspect attribute in the PostSharp library. It can intercept entry and exit from method like this:
[Serializable]
[MulticastAttributeUsage(MulticastTargets.Method, Inheritance = MulticastInheritance.Multicast)]
public class InterceptAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{ }
public override void OnExit(MethodExecutionArgs args)
{ }
}
public class A
{
[Intercept]
public void foo() { }
}
And my question is "How does it work?" What should I do to write my own attribute, that will be able to intercept entry and exit from method (without PostSharp using ofcourse)?
First of all, I'd recommend reading following documentation for internal workings (the "how does it work" sections and others). Basically, the attributes are translated into relevant code at the build time (actually, mostly after the build but still while building). There's a notion of MSBuild task that specifies the code to be run during the build process. The code executes after the compilation is done and looks for specific attributes (like InterceptAttribute) and may perform changes to the compiled code. Runtime edits to the code may be executed while using Mono.Cecil library (it allows to inject/remove IL code). Once again, to clarify:
The code is built with attributes assigned.
During the build, specific code is called per BuildTasks written
BuildTasks use reflection to find pieces of code that contain necessary attributes
BuildTasks use Mono.Cecil to inject code dynamically to those pieces found
Build is complete. Your compiled dll now contains not only the code written, but also the attributes changed into some code. I'd suggest looking at the assembly with ILSpy or similar decompilers to see the difference between your initial code and generated one.
I'd recommend looking at KindOfMagic codes to see how automatic INotifyPropertyChanged's RaisePropertyChanged is implemented as attribute. It provides valuable insights into creating custom aspects, though it may prove hard and tedious process.
Apologies if these are extremely basic questions, but let's say I'm using the void Add(T item) function of BlockingCollection:
1) How would I override the Add function, i.e. if I want to add a check at the beginning and then call the base function, is this possible to do, and if so, would the code look something like this?
protected sealed class BlockingCollection<T> : IEnumerable<T>
{
protected override void Add(T item)
{
// do something here
// call base blockingcollection add function, something like return base.Add(item)??
}
}
2) If instead of calling the base function, I wanted to actually modify the Add code, is there a way to get the underlying code for the Add function? Would I use something such as Reflection? If so, is there any way to get the underlying code without writing my own program and using reflection to get the method code (i.e. can I get the underlying method code within the Visual Studio IDE itself without having to write / compile / run code every time I want to get the underlying code of a method?)?
IEnumerable doesn't have an "Add" method; you'd have to implement your own. ICollection does, however!
Also, because IEnumerable/ICollection are interfaces, not classes, there's no existing implmementation for you to override. You have to do that part yourself.
Edit for possible additional extra super duper correctness:
If you're trying to subclass BlockingCollection and you want to do some additional "stuff" before T is added via "Add", you could do it like this:
public class Foo<T> : BlockingCollection<T>
{
public new void Add(T item)
{
base.Add(item);
base.Add(item);
}
}
So, this extremely simple implementation will add anything you put into your Foo via "Add" twice.
I hope you are aware that you are creating a brand new BlockingCollection class, you aren't modifying the System.Collections.Concurrent.BlockingCollection<T> class that's part of the BCL.
Actually modifying the library version of BlockingCollection<T>.Add would be quite difficult to say the least. It's distributed as a signed binary, and .NET doesn't provide a detours-style mechanism. Although DynamicMethod allows you to add new methods to existing classes, I don't think you can use it to replace existing methods.
1) Yes, that is the correct way to do what you are asking.
2) You use a decompiler to view source code for a library API you are choosing to override. This is done by you, the human, and not as part of program execution.
Reflection is a bit different. It allows your code to access an API at run time, but does not access nor expose the API's source code. There are a lot of resources out there, but you could start on MSDN.
Update:
Since the method you are overriding is void, you may not change the implementation by returning something. Try this:
protected override void Add(T item)
{
// do something here
// call base blockingcollection add function
base.Add(item);
// this is unnecessary, but you could do it for giggles
return;
}
If the original library has allowed you to override Add then the pseudo-code you show is along the right track. You do need a bit of modification though if I understand your question properly.
First, you would create your own class, inheriting the old class and if not already done by the old class implementing the IEnumerable interface. Of course if the old class is "sealed" you will not be able to do this.
protected sealed class MyBlockingCollection<T> : BlockingCollection<T>, IEnumerable<T>
{
protected override void Add<T>(T item)
{
}
}
now marking your class as sealed will prevent anyone from further overriding methods exposed. If the old class is marked sealed, you will not be able to do this.
To see the code, you will need to decompile the library, using a tool which could be easy or difficult depending on the level of obfuscation that may or may not be employed to keep you from doing just that.
Edit: just winging the code, you should check a reference to ensure you have the appropriate syntax for what you are trying to do.
C# 3.0 Extension methods add extensions to the base Type making calling that method on all instances of that Type legal.
Now, JavaScript I know implements IDispatchEx through which it's possible to add methods to a specific instance.
So how do I add a set of methods to an 'instance' of a C# class? I know this is a Dynamic vs. Static Languages holy war territory. :) Let me clarify my intention is NOT that.
I just want to be able to add a set of events to an interface depending on the class implementing that interface.
I was able to do that using Generics
inteface ISample<T> { T SupportedEvents; }
class Sample : ISample<UIWidgetEvent> { }
class Sample2 : ISample<NonVisualUIWidget> { }
class UIWidgetEvent { public EventHandler Clicked; }
class NonVisualUIWidget {public EventHandler Expired;}
class TestSample
{
public void Test()
{
new Sample().SupportedEvents.Clicked += ...
new Sample2().SupportedEvents.Expired += ...
}
}
Then I didn't like SupportedEvents I want to be able to say
new Sample().Clicked +=...
Then I thought JavaScript (I know C# is not JS :))... AND IDispatchEx, IL Weaving, Reflection.Emit etc. etc. and thought may be there's a way to do this... [Design time support would be nice but I can live without]
Yes, I probably could do this "instance augmentation" with a Visitor pattern.
[Not sure if I could get the syntatic sugar though]
Comments?
Well, you could create a DynamicMethod instance for your "new" methods, but statically attaching them to an existing instance at runtime wouldn't work due to the fact it plain wouldn't compile.
You might (I haven't tried this) be able to emit the opcodes into an in-memory assembly, but that's about as far away from being "Syntactically sweet" as you can get (would involve a lot of reflection and InvokeMember calls, I would think)
It also might be worth looking into Extension Methods - although I've never tried attaching events or event-like methods via extension methods...and they are 3.5 only, so that may limit you.
The nicest looking, "pure C#" implementation is probably something very similar to what you've already got with the generic/interface setup...
Honestly, if you're looking for something with true "dynamic support" like this, I'd do this kind of stuff in a DLR-capable language (like IronPython) and call into it from your C# stuff.
I have a class holding complex scientific computations. It is set up to only allow a user to create a properly instantiated case. To properly test the code, however, requires setting internal state variables directly, since the reference documents supply this data in their test cases. Done improperly, however, it can invalidate the state.
So I must have the ability, a member function, to set internal variables from the unit test programs. But I want to strongly discourage normal users from calling this function. (Yes, a determined user can muck with anything... but I don't want to advertise that there is a way to do something wrong.)
It would be nice to be able to tell Intellisense to not show the function, for instance.
The best solution I have at the moment is to just name the function something like: DangerousSet().
What other options do I have?
Follow-Up
I found Amy B's answer most useful to my situation. Thanks!
Mufasa's suggestion to use reflection was great, but harder to implement (for me).
Chris' suggestion of using a decorator was good, but didn't pan out.
BFree's suggestion on XML is also good, and was already in use, but doesn't really solve the problem.
Finally, BillTheLizard's suggestion that the problem is in the source documents is not something I can control. International experts publish highly technical books and journal articles for use by their community. The fact that they don't address my particular needs is a fact of life. There simply are no alternative documents.
You can use InternalsVisibleToAttribute to mark internal members as visible to your test assembly. It seems to shine when used in this context, though its not quite "friend".
Mark your DangerousSet function internal instead of public.
In Properties\AssemblyInfo.cs of the project containing DangerousSet:
[assembly:InternalsVisibleTo("YourTestAssembly")]
If you have two test assemblies for whatever reason, the syntax is:
[assembly:InternalsVisibleTo("TestAssembly1"),
InternalsVisibleTo("TestAssembly2")]
Decorate your method with this attribute:
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
This will hide it from Intellisense.
EDIT:
But apparently this has a rather significant caveat: "In Visual C#, EditorBrowsableAttribute does not suppress members from a class in the same assembly." Via MSDN.
Suppose you want to test this object by manipulating its fields.
public class ComplexCalculation
{
protected int favoriteNumber;
public int FavoriteNumber
{
get { return favoriteNumber; }
}
}
Place this object in your test assembly/namespace:
public class ComplexCalculationTest : ComplexCalculation
{
public void SetFavoriteNumber(int newFavoriteNumber)
{
this.favoriteNumber = newFavoriteNumber;
}
}
And write your test:
public void Test()
{
ComplexCalculationTest myTestObject = new ComplexCalculationTest();
myTestObject.SetFavoriteNumber(3);
ComplexCalculation myObject = myTestObject;
if (myObject.FavoriteNumber == 3)
Console.WriteLine("Win!");
}
PS: I know you said internal, but I don't think you meant internal.
It sounds like your real problem is in your reference documents. You shouldn't test cases that are impossible to encounter under proper use of your class. If users shouldn't be allowed to change the state of those variables, then neither should your tests.
You can also use reflection. Google search turned up Unit testing private methods using reflection.
Can your test code include a subclass of the calculations class? If so, you can mark the function protected and only inheritors will be able to use it. I'm pretty sure this also takes it out of intellisense, but I could be wrong about that.
What I've done in the past is I put XML Comments by the method and used the section to write in big bold letters. DON'T USE THIS METHOD or whatever. That way, if someone tried to use it, Intellisense would give them a nice warning.