I can't seem to figure out why this is throwing "Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type." Specifically this part method.CreateDelegate(eventInfos[0].EventHandlerType, new Commands());
//These are defined at the top of the class
public delegate Task MessageReceivedAsyncDelegate(SocketMessage arg);
public delegate void MessageReceivedDelegate(SocketMessage arg);
public event MessageReceivedAsyncDelegate MessageReceivedCommandAsync;
public event MessageReceivedDelegate MessageReceivedCommand;
//These are defined at the top of the class
Type B = typeof(Base);
Type C = typeof(Commands);
MethodInfo[] methods = C.GetMethods();
foreach (MethodInfo method in methods)
{
EventInfo[] eventInfos = B.GetEvents();
if(method.GetCustomAttributes(typeof(SubscribeToMessageRecivedAttribute)).Any()
{
if (method.ReturnType == typeof(Task))
{
try { eventInfos[0].AddEventHandler(C, method.CreateDelegate(eventInfos[0].EventHandlerType, new Commands())); }
catch(Exception exception) { Console.WriteLine(exception); }
}
else eventInfos[1].AddEventHandler(C, method.CreateDelegate(eventInfos[1].EventHandlerType, new Commands()));
}
}
Method which it's trying to add
public partial class Commands : ModuleBase<SocketCommandContext>
{
[SubscribeToMessageRecived]
public static async Task Mock(SocketMessage arg)
{
Console.WriteLine("Mocking");
if (Base.mockList.Contains((int)arg.Author.Id))
{
char[] msgArray = arg.Content.ToCharArray();
for (int i = 0; i < arg.Content.Length; i++)
{
if (DaMef.RandomRange(0,3) == 1) msgArray[i] = msgArray[i].ToString().ToLower().ToCharArray()[0];
else msgArray[i] = msgArray[i].ToString().ToUpper().ToCharArray()[0];
}
string finalString = msgArray.ToString();
await arg.Channel.SendMessageAsync(finalString + "\nhttps://imgur.com/a/HsiBmYc");
}
}
}
I'm trying to subscribe all methods in the Commands with "SubscribeToMessageRecivedAttribute" to an event.
There are answers online but none seem to be it. (Or maybe I just didn't understand them.) I've never used reflections and have barely used events so sorry if it's something stupid.
Related
I have an EventAggregator Implementation that distinguishes between Event Types and calls all registered Callbacks with that Event Type as Parameter, so the Publish-Method looks like this:
public void Publish<T>(T args) where T : IEvent
{
if (callbacks != null)
{
var callbacksByEvent = callbacks.GetCallbacksByEventType(typeof(T));
if (callbacksByEvent != null)
{
foreach (var callback in callbacksByEvent)
{
if (callback is Action<T>)
{
Task.Run(() => ((Action<T>)callback)(args));
}
}
}
}
}
The IEvent is just an empty Marker Interface for the Event Classes. It works perfectly fine when passing a hardcoded Implementation like SomethingHappenedEvent : IEvent into the Method, but I wanted to create a Notification Window where any IEvent Implementation can be assigned to the Buttons "Yes", "No", "Cancel" and they will be executed when clicked:
private IEvent CancelEvent;
private void Cancel()
{
if (CancelEvent != null)
{
EventAggregator.Publish(CancelEvent);
}
}
In this Scenario, callbacks.GetCallbacksByEventType(typeof(T)) returns NULL, because T is IEvent, but the Callback Methods are registered with the real Implementation:
EventAggregator.Subscribe<SomethingHappenedEvent>(OnSomethingHappened)
If I change it to callbacks.GetCallbacksByEventType(args.GetType()), I get the Callback List that I expect, but the if-statement
if(callback is Action<T>)
still returns false, because T is still IEvent and the Method is not an Action<IEvent>, but an Action<SomethingHappenedEvent>.
So the question is: how do I get the T to become my SomethingHappenedEvent?
I can get the actual Type from Class at Runtime using .GetType(), so it should be possible? I'm on .NET Framework 4.5.
I read a bunch of Stackoverflow Posts on Generics and Interfaces but couldn't quite find what I was looking for! Can you help please? Thank you for reading all of this :D
//Edit: Sorry, here's the code for the GetCallbacksByEventType Method:
internal List<Delegate> GetCallbacksByEventType(Type eventType)
{
List<Delegate> callbacks;
lock (delegateTable)
{
if (!delegateTable.ContainsKey(eventType))
{
return null;
}
List<WeakDelegate> weakReferences = delegateTable[eventType];
callbacks = new List<Delegate>(weakReferences.Count);
for (int i = weakReferences.Count - 1; i > -1; --i)
{
WeakDelegate weakReference = weakReferences[i];
if (weakReference.IsAlive)
{
callbacks.Add(weakReference.GetDelegate());
}
else
{
weakReferences.RemoveAt(i);
}
}
if (weakReferences.Count == 0)
{
delegateTable.Remove(eventType);
}
}
return callbacks;
}
and the WeakReference Class is:
internal sealed class WeakDelegate
{
readonly Type DelegateType;
readonly MethodInfo DelegateFunction;
readonly WeakReference DelegateTarget;
public Delegate GetDelegate()
{
object target = DelegateTarget.Target;
if (target != null)
{
return Delegate.CreateDelegate(DelegateType, target, DelegateFunction);
}
return null;
}
}
I've used delegates in the past so I'm familiar with their use and benefits. I've also done a lot of reading/research, but I'm trying to wrap my head around this and getting nowhere. I'd like to use a delegate (I believe) to encapsulate some code or use a delegate within a method to call some outside code.
I'm using the same code in 20 different places to wrap an entity framework update in a transaction. I would like the code in one place; however, I can't do it in a method by itself because there is a middle part that will change each time. I'm looking for some ideas / clarification on how I can best do this (.net 3.5, ms sql 2010). - thnx
code sample:
void AddItem(string objDetails)
{
// setup method specific entity objects
SomeObject obj = new SomeObject { Details = objDetails };
//////// Begin transaction code that I would like to encapsulate ///////
bool success = false;
using (Entities data = new Entities())
{
for (int i = 0; i < s.BaseSettings.CommandRetries; i++)
{
using (TransactionScope transaction = new TransactionScope())
{
try
{
//////////////////////////////////////////////////////////////
///////// BEGIN Code that I would like to change / call different each time ////////
data.AddToSOMEOBJECTs(obj);
//////////////// END //////////////////////////////////
//// RETURN TO ENCAPSULATED CODE ////
data.SaveChanges(false);
transaction.Complete();
success = true;
break;
}
catch (Exception ex)
{
if (ex.GetType() != typeof(UpdateException))
{
throw new Exception("Unhandled db exception.");
}
}
}
}
if (success)
{
data.AcceptAllChanges();
}
else
{
throw new Exception();
}
}
}
You pass the function a delegate (or lambda) that does the custom bit
like this
void AddItem<T>(string objDetails, Func<T> custom) {
.
. common
.
.
T someReturn = custom();
.
. common
.
}
add call like this perhaps:
Func<int> custom = () => {
// do something custom
return 9;
}
// Call common function
AddItem<int>(..., custom);
All that matters is that the interface for the Func matches what you need.
You can pass different methods by using a delegate and an event. Here's an example of a class that does this:
class SampleClass
{
public delegate void TransactionDelegate();
public event TransactionDelegate MyTransactionDelegate;
public void DoSomething()
{
MyTransactionDelegate();
}
}
You can then use a lambda expression to pass methods to the event like this:
class MainClass
{
public static void Main (string[] args)
{
var test = new SampleClass();
test.MyTransactionDelegate += () => {Console.WriteLine("Success");};
test.DoSomething();
}
}
Why is Visual Studio 2010 telling me "'System.Delegate' does not contain a definition for 'EndInvoke'" when I call job.Delegate.EndInvoke()? How do I fix it? Note that it likes BeginInvoke() just fine, and doesn't complain if I add EndInvoke() immediately after BeginInvoke() (thought hat doesn't accomplish what I want).
I have a little JobTracker class for tracking backup jobs:
public class JobTracker
{
private class Job
{
public Account Account { get; set; }
public IAsyncResult Result { get; set; }
public Delegate Delegate { get; set; }
public bool IsCompleted { get { return result.IsCompleted } }
public string Instance { get { return Account.Instance } }
}
public List<Job> Running = new List<Job>;
public void AddJob(Account a, IAsyncResult result, Delegate del)
{
var j = new Job { Account = a, Result = result, Delegate = del };
Running.Add(j);
}
public void RemoveJob(Job job)
{
Running.Remove(job);
}
public bool IsInstanceRunning(string instance)
{
return (Running.Count(x => x.Instance == instance) > 0);
}
}
These backup jobs will happen asynchronously via BeginInvoke()/EndInvoke(). The calling code (simplified) looks something like this:
public void BackupAccounts(IEnumerable<Account> accounts, int maxconcurrent = 4)
{
// local copy
List<Accounts> myaccounts = accounts.ToList();
var jobs = new JobTracker();
while (myaccounts.Count > 0)
{
// check our running jobs
foreach (var job in jobs.Running)
{
if (job.IsCompleted)
{
// PROBLEM LINE:
job.Delegate.EndInvoke();
jobs.RemoveJob(job);
}
}
// more jobs!
while (jobs.Count < maxconcurrent)
{
int i = 0;
Account account = null;
// choose the next account on a free instance
while (int < accounts.Count)
{
account = accounts[i];
// instance in use?
if (jobs.InstanceIsRunning(account.Instance))
{
i += 1;
continue;
}
else
{
// start the job
accounts.RemoveAt(i);
BackupDelegate del = new BackupDelegate(BackupAccount, account);
IAsyncResult result = del.BeginInvoke();
jobs.AddJob(account, result, del);
}
}
}
// we're all full up, give it some time to work
Thread.Sleep(2000);
}
}
PS - I know this code can be greatly simplified. It's a first, get-it-working iteration -- I just can't figure out why VS doesn't like it.
When you call BeginInvoke, you're calling it on a specific subclass of Delegate. When you call EndInvoke, you're trying to call it on System.Delegate itself, which won't work. Each subclass declares its own Invoke/BeginInvoke/EndInvoke set of methods - which it has to, given that the signatures of the methods varies according to the signature of the exact delegate type you're talking about. If you look at the documentation for System.Delegate you won't find any of those methods there.
It's not really clear what your code is trying to achieve, but if you want to call EndInvoke, you'll need to make Job.Delegate a specific delegate type.
Because EndInvoke doesn't exist on Delegate. Instead you should have your Job class hold a reference to a BackupDelegate.
I want to write a rule that will fail if an object allocation is made within any method called by a method marked with a particular attribute.
I've got this working so far, by iterating up all methods calling my method to check using CallGraph.CallersFor(), to see if any of those parent methods have the attribute.
This works for checking parent methods within the same assembly as the method to be checked, however reading online, it appears that at one time CallGraph.CallersFor() did look at all assemblies, however now it does not.
Question: Is there a way of getting a list of methods that call a given method, including those in a different assembly?
Alternative Answer: If the above is not possible, how do i loop through every method that is called by a given method, including those in a different assembly.
Example:
-----In Assembly A
public class ClassA
{
public MethodA()
{
MethodB();
}
public MethodB()
{
object o = new object(); // Allocation i want to break the rule
// Currently my rule walks up the call tree,
// checking for a calling method with the NoAllocationsAllowed attribute.
// Problem is, because of the different assemblies,
// it can't go from ClassA.MethodA to ClassB.MethodB.
}
}
----In Assembly B
public var ClassAInstance = new ClassA();
public class ClassB
{
[NoAllocationsAllowed] // Attribute that kicks off the rule-checking.
public MethodA()
{
MethodB();
}
public MethodB()
{
ClassAInstance.MethodA();
}
}
I don't really mind where the rule reports the error, at this stage getting the error is enough.
I got round this issue by adding all referenced dlls in my FxCop project, and using the code below, which builds a call tree manually (it also adds calls for derived classes to work round another problem i encountered, here.
public class CallGraphBuilder : BinaryReadOnlyVisitor
{
public Dictionary<TypeNode, List<TypeNode>> ChildTypes;
public Dictionary<Method, List<Method>> CallersOfMethod;
private Method _CurrentMethod;
public CallGraphBuilder()
: base()
{
CallersOfMethod = new Dictionary<Method, List<Method>>();
ChildTypes = new Dictionary<TypeNode, List<TypeNode>>();
}
public override void VisitMethod(Method method)
{
_CurrentMethod = method;
base.VisitMethod(method);
}
public void CreateTypesTree(AssemblyNode Assy)
{
foreach (var Type in Assy.Types)
{
if (Type.FullName != "System.Object")
{
TypeNode BaseType = Type.BaseType;
if (BaseType != null && BaseType.FullName != "System.Object")
{
if (!ChildTypes.ContainsKey(BaseType))
ChildTypes.Add(BaseType, new List<TypeNode>());
if (!ChildTypes[BaseType].Contains(Type))
ChildTypes[BaseType].Add(Type);
}
}
}
}
public override void VisitMethodCall(MethodCall call)
{
Method CalledMethod = (call.Callee as MemberBinding).BoundMember as Method;
AddCallerOfMethod(CalledMethod, _CurrentMethod);
Queue<Method> MethodsToCheck = new Queue<Method>();
MethodsToCheck.Enqueue(CalledMethod);
while (MethodsToCheck.Count != 0)
{
Method CurrentMethod = MethodsToCheck.Dequeue();
if (ChildTypes.ContainsKey(CurrentMethod.DeclaringType))
{
foreach (var DerivedType in ChildTypes[CurrentMethod.DeclaringType])
{
var DerivedCalledMethod = DerivedType.Members.OfType<Method>().Where(M => MethodHidesMethod(M, CurrentMethod)).SingleOrDefault();
if (DerivedCalledMethod != null)
{
AddCallerOfMethod(DerivedCalledMethod, CurrentMethod);
MethodsToCheck.Enqueue(DerivedCalledMethod);
}
}
}
}
base.VisitMethodCall(call);
}
private void AddCallerOfMethod(Method CalledMethod, Method CallingMethod)
{
if (!CallersOfMethod.ContainsKey(CalledMethod))
CallersOfMethod.Add(CalledMethod, new List<Method>());
if (!CallersOfMethod[CalledMethod].Contains(CallingMethod))
CallersOfMethod[CalledMethod].Add(CallingMethod);
}
private bool MethodHidesMethod(Method ChildMethod, Method BaseMethod)
{
while (ChildMethod != null)
{
if (ChildMethod == BaseMethod)
return true;
ChildMethod = ChildMethod.OverriddenMethod ?? ChildMethod.HiddenMethod;
}
return false;
}
}
Did you give it a try in this way,
StackTrace stackTrace = new StackTrace();
MethodBase methodBase = stackTrace.GetFrame(1).GetMethod();
object [] items = methodBase.GetCustomAttributes(typeof (NoAllocationsAllowed));
if(items.Length > 0)
//do whatever you want!
What do I have to do to say that InvokeMethod can invoke a method and when using special options like Repeat it shall exexute after the Repeat.
My problem for now is that the method will already exexute before it knows that it has to be called 100 times.
class Program
{
static void Main()
{
const bool shouldRun = true;
new MethodExecuter()
.ForAllInvocationsUseCondition(!Context.WannaShutDown)
.InvokeMethod(A.Process).Repeat(100)
.When(shouldRun).ThenInvokeMethod(B.Process).Repeat(10)
.ForAllInvocationsUseCondition(Context.WannaShutDown)
.When(shouldRun).ThenInvokeMethod(C.Process);
}
}
MethodExpression
public class MethodExpression
{
private bool _isTrue = true;
private readonly MethodExecuter _methodExecuter;
public MethodExpression(bool isTrue, MethodExecuter methodExecuter)
{
_isTrue = isTrue;
_methodExecuter = methodExecuter;
}
public MethodExecuter ThenInvokeMethod(Action action)
{
if (_isTrue)
{
action.Invoke();
_isTrue = false;
}
return _methodExecuter;
}
}
MethodExecuter
public class MethodExecuter
{
private bool _condition;
private int _repeat = 1;
public MethodExpression When(bool isTrue)
{
return new MethodExpression(isTrue && _condition, this);
}
public MethodExecuter InvokeMethod(Action action)
{
if (_condition)
{
for (int i = 1; i <= _repeat; i++)
{
action.Invoke();
}
}
return this;
}
public MethodExecuter ForAllInvocationsUseCondition(bool condition)
{
_condition = condition;
return this;
}
public MethodExecuter Repeat(int repeat)
{
_repeat = repeat;
return this;
}
}
Use a final method ("go", or "execute") to actually kick things off.
new MethodExecuter()
.ForAllInvocationsUseCondition(!Context.WannaShutDown)
.InvokeMethod(A.Process).Repeat(100)
.When(shouldRun).ThenInvokeMethod(B.Process).Repeat(10)
.ForAllInvocationsUseCondition(Context.WannaShutDown)
.When(shouldRun).ThenInvokeMethod(C.Process)
.Go();
What you've provided looks a bit like programming a workflow or state machine. In order to capture invocations and respect conditions during execution, you'd need to change your approach slightly.
Instead of invoking actions as they come in, consider pushing your actions into a queue and then providing an mechanism to run the state machine.
new MethodInvoker()
.ForAllInvocationsUseCondition(true)
.InvokeMethod( Process.A ).Repeat(100)
.Run();
There are a lot of ways to skin this cat, but I think one source of this difficulty is in the fact that you actually invoke the method within the InvokeMethod() method (go figure!).
Typically, we use fluent APIs to turn syntax that is evaluated from the inside-out into something that can be expressed in a left-to-right fashion. Thus, the expression builder components of the interface are used to build up state throughout the expression, and only at the end does the "real work" happen.
One solution to your immediate problem is to queue up each action with its associated options (invocation conditions, repeat count, etc.), and add some ExecuteAll() method to MethodExecuter that dequeues and executes the fully configured actions at the end of the member chain.
Another solution would be to put all of the execution options inside the InvokeMethod() method; something like:
.Invoke(x => x.Method(A.Process).Repeat(100))
This method would look something like:
public MethodExecuter Invoke(Action<IExecutionBuilder> executionBuilder)
{
var builder = new ExecutionBuilder();
executionBuilder(builder);
var action = builder.Action;
var repeat = builder.RepeatCount;
if (_condition)
{
for (int i = 1; i <= repeat; i++)
{
action();
}
}
return this;
}
I haven't worked through this in Visual Studio, but the other items would be something like:
public interface IExecutionBuilder
{
IExecutionBuilder Method(Action action);
IExecutionBuilder Repeat(int count);
}
public class ExecutionBuilder : IExecutionBuilder
{
public ExecutionBuilder()
{
RepeatCount = 1; // default to repeat once
Action = () => {}; // default to do nothing, but not null
}
public IExecutionBuilder Method(Action action)
{
Action = action;
return this;
}
public IExecutionBuilder Repeat(int repeat)
{
RepeatCount = repeat;
return this;
}
public int RepeatCount { get; private set; }
public Action Action { get; private set; }
}
Note that RepeatCount and Action are not exposed on the interface. This way, you will not see these members when calling .Invoke(x => x., but will have access to them when using the concrete ExecutionBuilder class inside the Invoke() method.
You could have a SetInvokeMethod and an Execute Method.
SetInvokeMethod(Action).Repeat(100).Execute()
In a sentence, your code is too "eager". The InvokeMethod method is called, and performs the action, before your fluent grammar structure tells your code how many times it should repeat.
To change this, try also specifying the method you are invoking as a private field in your methodInvoker, then include a command that is a "trigger" to actually perform the commands. The key is "lazy evaluation"; in a fluent interface, nothing should be done until it has to; that way you have most of the control over when it does happen.
public class FluentMethodInvoker
{
Predicate condition = ()=>true;
Predicate allCondition = null;
Action method = ()=> {return;};
bool iterations = 1;
FluentMethodInvoker previous = null;
public FluentMethodInvoker(){}
private FluentMethodInvoker(FluentMethodInvoker prevNode)
{ previous = prevNode; }
public FluentMethodInvoker InvokeMethod(Action action)
{
method = action;
}
//Changed "When" to "If"; the function does not wait for the condition to be true
public FluentMethodInvoker If(Predicate pred)
{
condition = pred;
return this;
}
public FluentMethodInvoker ForAllIf(Predicate pred)
{
allCondition = pred;
return this;
}
private bool CheckAllIf()
{
return allCondition == null
? previous == null
? true
: previous.CheckAllIf();
: allCondition;
}
public FluentMethodInvoker Repeat(int repetitions)
{
iterations = repetitions;
return this;
}
//Merging MethodExecuter and MethodExpression, by chaining instances of FluentMethodInvoker
public FluentMethodInvoker Then()
{
return new FluentMethodInvoker(this);
}
//Here's your trigger
public void Run()
{
//goes backward through the chain to the starting node
if(previous != null) previous.Run();
if(condition && CheckAllIf())
for(var i=0; i<repetitions; i++)
method();
return;
}
}
//usage
class Program
{
static void Main()
{
const bool shouldRun = true;
var invokerChain = new FluentMethodInvoker()
.ForAllIf(!Context.WannaShutDown)
.InvokeMethod(A.Process).Repeat(100)
.When(shouldRun)
.Then().InvokeMethod(B.Process).Repeat(10)
.ForAllIf(Context.WannaShutDown)
.When(shouldRun)
.Then().InvokeMethod(C.Process);
//to illustrate that the chain doesn't have to execute immediately when being built
invokerChain.Run();
}
}