I want to be able to specify a method in another method.
Something like
public class Binder
{
public void Bind(whatShouldIWriteHere?)
{
// do stuff with the MethodInfo
}
}
so that I can do:
public class A
{
public void DoIt(string tmp)
{
}
}
var binder = new Binder()
binder.Bind<A>(x => x.DoIt);
Instead of:
var method = typeof(A).GetMethod("DoIt");
binder.Bind(method);
Is that possible? :)
Pass the method as a delegate and use the Delegate.Method property.
In your case Binder.Bind would be like:
public void Bind(Delegate del)
{
var info = del.Method;
//Add your logic here.
}
And to pass a method to it:
var binder = new Binder();
var instance = new A();
binder.Bind(new Action<string>(instance.DoIt))
Related
I heard that passing an action, function or delegate to a public method is a security issue.
I want to understand why or how this can be exploited because I cannot find a way to do it.
At least.. is it a best practice to not pass delegates to classes?
Examples of so called vulnerable code:
Public constructor action:
public class MyClass { public MyClass(Action doSomething) { doSomething?.Invoke(); } }
with the calling code in another project using my code as a reference:
var securityIssueActionOutsideOfMyControl = new Action(() => { ... });
var instance = new MyClass(securityIssueActionOutsideOfMyControl);
Public constructor action with parameter:
public class MyClass
{
public MyClass(Action<string> doSomething)
{
doSomething?.Invoke("something");
}
}
with the calling code in another project using my code as a reference:
var securityIssueActionOutsideOfMyControl = new Action<string>((someParameter) => { ... });
var instance = new MyClass(securityIssueActionOutsideOfMyControl);
Same so called issue can happen with functions or delegates passed to public constructor.
Public method with action:
public class MyClass { public void MyAction(Action doSomething) { doSomething?.Invoke(); } }
with the calling code in another project using my code as a reference:
var securityIssueActionOutsideOfMyControl = new Action(() => { ... });
var instance = new MyClass();
instance.MyAction(securityIssueActionOutsideOfMyControl);
public class MyClass { public void MyAction(Action<string> doSomething) { doSomething?.Invoke("some string"); } }
with the calling code in another project using my code as a reference:
var securityIssueActionOutsideOfMyControl = new Action<string>((someParameter) => { ... });
var instance = new MyClass();
instance.MyAction(securityIssueActionOutsideOfMyControl);
Same so called issue can happen with functions or delegates passed to public methods.
How is it different than the following code using events?
var securityIssueActionOutsideOfMyControl = new Action(() => { ... });
var instance = new MyClass();
instance.MyEvent += (s, e) => securityIssueActionOutsideOfMyControl;
Or how it is different from calling the method directly in a different project?
var securityIssueActionOutsideOfMyControl = new Action(() => { ... });
securityIssueActionOutsideOfMyControl?.Invoke();
I want to pass some parameters to function that is being called using reflection in a universal windows App. Below is the code which I tried and I am getting an exception "Parameters Count mismatch.". please advice me.
public class myClass
{
public async void btn_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
Type type = Type.GetType("moto_Windows.Actions.NextViewAction");
object[] mParam = new object[] { 5, 10 };
var nva = Activator.CreateInstance(type);
await (dynamic)type.GetTypeInfo().GetDeclaredMethod("NextView").Invoke(nva, mParam);
}
}
The class I am trying to invoke look like below
namespace moto_Windows.Actions
{
public class NextViewAction
{
public NextViewAction(object [] obj)
{
//Constructor
}
public async void NextView()
{
//Method to be invoked.
}
}
}
Finally I solved this by passing values in a dictionary through a contructor, my code is
Type type = Type.GetType("moto.Actions." + ctrl.Action.name);
ctrl = (Carrot_Control)btn.DataContext;
Dictionary<string, object> _dict = new Dictionary<string, object>();
dict.Add("a", 5);
_dict.Add("b", 10);
var t = Activator.CreateInstance(type, _dict);
await (dynamic)type.GetTypeInfo().GetDeclaredMethod("NextView").Invoke(t, null);
and the class i tried to invoke
namespace moto_Windows.Actions
{
public class NextViewAction
{
public NextViewAction(Dictionary<string,object> _dict)
{
//Constructor
string a = _dict[a];
string b = _dict[b];
}
public async void NextView()
{
//Method to be invoked.
}
}
}
please post if anybody has better answer.
I have this domain:
public class GenClass<T> { }
public class Type1 { }
public class Type2 { }
public class GenType1 : GenClass<Type1> { }
public class GenType2 : GenClass<Type1> { }
public class GenType3 : GenClass<Type2> { }
public class GenType4 : GenClass<string> { }
public class GenType5 : GenClass<int> { }
and this logic:
public class SomeClass {
public void Add<T>(GenClass<T> t) { }
}
and this consumer:
public class Consumer {
public void Method() {
var some = new SomeClass();
some.Add(new GenType1());
some.Add(new GenType2());
some.Add(new GenType3());
some.Add(new GenType4());
some.Add(new GenType5());
}
}
But instead of adding each GenType(n) separately, I create a method like this:
public void AddFromAssembly<TAssembly>(SomeClass some, Type baseType) {
var list = typeof(TAssembly).Assembly.GetTypes()
.Where(t => baseType.IsAssignableFrom(t)
&& !baseType.Equals(t))
.ToList();
list.ForEach(type => {
var ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null,
Type.EmptyTypes, null);
var obj = ctor.Invoke(new object[] { });
some.Add(obj); //????
});
}
and want to call it like this:
public class Consumer {
public void Method() {
var some = new SomeClass();
AddFromAssembly<GenType1>(some, typeof(GenClass<>));
}
}
But some.Add method is a generic method and ctor.Invoke method returns an object.
Have you any idea to solve this problem? Thanks in advance.
UPDATE The question was incomplete, I fix it. Thanks for review.
Either do this:
Add<object>(obj); //this will work with T typed as object
or:
typeof(Some).GetMethod("Add").MakeGenericMethod(new [] { typeof(obj.GetType()).Invoke(some, new [] { obj });
The reflection version will use the exact type of obj for T at runtime.
Type parameters to generics are a compile time required and can't be determine at runtime (unless you want to get into the hassle of creating class definitions at runtime).
What you'll likely need to do is create a second version of the method that is typed for "object" and use that instead.
Is there any way so that you can call a function with a variable?
variable+"()";
or something like that, or would I have to use if statements?
A switch seems like it might be the answer, so if the variable's value=var1 I want it to execute var1(); if the value is var2 I want it to execute var2(); how would I code it?
Basically, I am trying to find a cleaner alternative to
if (variable == var1)
{
var1();
}
if (variable == var2)
{
var2();
}
It would be possible to use reflection to find a method in an object and call that method, but the simplest and fastest would be to simply use a switch:
switch (variable) {
case "OneMethod": OneMethod(); break;
case "OtherMethod": OtherMethod(); break;
}
You could use Reflection http://msdn.microsoft.com/en-us/library/ms173183(v=vs.80).aspx to access any function or member by name. It takes some getting used to though. It also has performance issues, so if you can avoid using it, you should.
This is what delegates are for:
Action f = ()=>Console.WriteLine("foo");
f();
I assume using strings is not actually a requirement.
You can use delegates. MSDN: http://msdn.microsoft.com/en-us/library/900fyy8e(v=vs.71).aspx
Exa:
public delegate void TestDelegate();
class TestDelegate
{
public static void Test()
{
Console.WriteLine("In Test");
}
public static void Main()
{
TestDelegate testDelegate = new TestDelegate(Test);
testDelegate();
}
}
You can use the MethodInfo class
Type yourtype = yourObject.GetType();
MethodInfo method = yourtype.GetMethod(variable);
var result = method.Invoke(yourObject,null);
string className = "My.Program.CoolClass"; //including namespace
string method= "Execute";
var type = Type.GetType(className);
var method = type.GetMethod(method);
method.Invoke(classObj, null);
Check out this post.
Use reflection.
http://dotnetslackers.com/Community/blogs/haissam/archive/2007/07/25/Call-a-function-using-Reflection.aspx
You can use MethodMethodInfo.
http://msdn.microsoft.com/en-us/library/system.reflection.methodinfo.aspx
http://msdn.microsoft.com/en-us/library/a89hcwhh.aspx
Here's a sample how you can call a method via reflection:
public class MyClass
{
public void PrintHello()
{
Console.WriteLine("Hello World");
}
}
//...
public void InvokeMethod(object obj, string method)
{
// call the method
obj.GetType().GetMethod(method).Invoke(obj, null);
}
//...
var o = new MyClass();
var method = "PrintHello";
//...
InvokeMethod(o, method);
(I will complete #Matthew's excellent answer):
var x = (Action) ( ()=>Print("foo") );
x();
p.s. you can fully variable names too:
private Dictionary<string, dynamic> my = new Dictionary<string, dynamic>();
my["x"] = .....
my["x"]();
public class FunctionTest
{
void Main()
{
Action doSomething;
doSomething = FirstFunction;
doSomething();
doSomething = SecondFunction;
doSomething();
}
void FirstFunction()
{
Console.Write("Hello, ");
}
void SecondFunction()
{
Console.Write("World!\n");
}
}
output:
Hello, World!
Doesn't get too much simpler than that.
I'm trying to create a url builder similar to the one in asp mvc except our methods are frequently changing parameters and breaking pages.
Does anyone know if it's possible to coerce c# into allowing event like syntax to be returned from a delegate like this:
new UrlBuilder2<FakeController>(x => { return x.ActionWithInt; });
The class would be similar to this:
public class UrlBuilder<TController>
{
public UrlBuilder2(Func<TController, TType> action)
{
}
}
Basically I want to know what Type to use for TType. Or if it's at all possible.
Edit -
I would (if possible) like to use just the method, similar to how you would assign an event ( clickEvent =+ myMethod;)
Not exactly sure what you want to achieve, but assuming you want to generate link simlar to this:
MyForm/MyMethod.aspx
based on WebForm (or any other class) like this:
public class MyForm {
public void MyMethod() {
// Something here
}
public void MethodWithParams(int i, string str) {
// Something here
}
}
You can use this builder (test included):
class UrlBuilder2<T> {
private readonly Expression<Func<T, object>> callExpression;
public UrlBuilder2(Expression<Func<T,object>> callExpression) {
this.callExpression = callExpression;
}
public override string ToString() {
MethodCallExpression call = (MethodCallExpression) callExpression.Body;
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}/{1}.aspx", call.Object.Type.Name, call.Method.Name);
var delimiter = "?";
var formalParams = call.Method.GetParameters();
for (int i = 0; i < formalParams.Length; i++) {
var actual = call.Arguments[i];
if (actual == null)
continue; // Do not put NULL to QueryString
var formal = formalParams[i].Name;
sb.AppendFormat("{0}{1}={2}", delimiter, formal, HttpUtility.HtmlEncode(actual.ToString()));
}
return sb.ToString();
}
}
[Test]
public void CanBuildUrlByClassAndMethodName() {
var str = new UrlBuilder2<MyForm>(c => c.MyMethod()).ToString();
str.Should().Be.EqualTo("MyForm/MyMethod.aspx");
}
[Test]
public void CanBuildUrlByMethodWithParams() {
var str = new UrlBuilder2<MyForm>(c => c.MethodWithParams(2, "hello")).ToString();
str.Should().Be.EqualTo("MyForm/MyMethod.aspx?i=2&str=hello");
}
All this will allow you to keep the links type-safe and refactoring advantages will be leveraged.
You will probably need to enhance the UrlBuilder2 but this should get you started.
If you just want to use name of a method to generate links you can do something like this:
class MyClass {
public void MyMethod() {}
}
class UrlBuilder3<T> {
Expression<Func<T, Action>> info;
public UrlBuilder3(Expression<Func<T, Action>> info) {
this.info = info;
}
public override string ToString() {
UnaryExpression exp = (UnaryExpression)info.Body;
MethodCallExpression createDelegate = (MethodCallExpression)exp.Operand;
// 0-Action,1-x,2-Delegate as Constant
ConstantExpression methodArgument = (ConstantExpression)createDelegate.Arguments[2];
MethodInfo method = (MethodInfo)methodArgument.Value;
return string.Format("{0}/{1}.aspx", typeof(T).Name, method.Name);
}
}
[Test]
public void UrlByDelegate() {
new UrlBuilder3<MyClass>(x => x.MyMethod).ToString()
.Should().Be.EqualTo("MyClass/MyMethod.aspx");
}
The tricky thing is correctly resolving the Expression tree. The code above works for this particular sample, but you will need to check it works for all your cases.
You can return a function pointer aka a delegate in c# as below.
public delegate int mydelegate(string s);
public class Test
{
mydelegate MyFunc(string s)
{
return (astring => astring.Length + s.Length);
}
}
This would allow you to attach the output of the function to an event.
var test = new Test();
someevent += test.MyFunc("this is a test");
Assuming that someevent took a function with the same signature as the delegate.