How does one determine if a MethodInfo represents the metadata for a lambda expression?
I think you are talking about anonymous methods.So, you can write an extension method for that and check whether the name of the method contains any invalid chars.Because the compiler generated methods contain invalid chars, you can use that feature to determine whether the method is anonymous or not:
public static bool IsAnonymous(this MethodInfo method)
{
var invalidChars = new[] {'<', '>'};
return method.Name.Any(invalidChars.Contains);
}
Test:
Func<int> f = () => 23;
Console.Write(f.Method.IsAnonymous()); // true
More elegant way would be validating the method name using IsValidLanguageIndependentIdentifier method, like this (method from this answer):
public static bool IsAnonymous(this MethodInfo method)
{
return !CodeGenerator.IsValidLanguageIndependentIdentifier(method.Name);
}
Remember in order to access IsValidLanguageIndependentIdentifier method you need to include the System.CodeDom.Compiler namespace.
The following code can do the trick. It is a bit long compared to the accepted answer, but alas the accepted answer does not make a proper distinction between lambdas and inner methods, which both get name mangled by the compiler. Hence the following provide two methods: IsAnonymous and IsInner.
By the way, the code should work under Mono as well (names seem to be mangled the same way but with a different magic tag under the hood).
public static class MethodInfoUtil
{
static readonly Regex MagicTagPattern = new Regex(">([a-zA-Z]+)__");
static readonly string AnonymousMagicTag;
static readonly string InnerMagicTag;
public static bool IsAnonymous(this MethodInfo mi)
{
return mi.Name.Contains(AnonymousMagicTag);
}
public static bool IsInner(this MethodInfo mi)
{
return mi.Name.Contains(InnerMagicTag);
}
public static string GetNameMagicTag(this MethodInfo mi, bool noThrow = false)
{
var match = MagicTagPattern.Match(mi.Name);
if (match.Success && match.Value is string value && !match.NextMatch().Success)
return value;
else if (noThrow)
return null;
else
throw new ArgumentException($"Cant find magic tag of {mi}");
}
// static constructor: initialize the magic tags
static MethodInfoUtil()
{
void Inner() { };
Action inner = Inner;
Action anonymous = () => { };
InnerMagicTag = GetNameMagicTag(inner.Method);
AnonymousMagicTag = GetNameMagicTag(anonymous.Method);
CheckThatItWorks();
}
[Conditional("DEBUG")]
static void CheckThatItWorks()
{
// Static mathods are neither anonymous nor inner
Debug.Assert(!((Func<int, int>)Math.Abs).Method.IsAnonymous());
Debug.Assert(!((Func<int, int>)Math.Abs).Method.IsInner());
// Instance methods are neither anonymous nor inner
Debug.Assert(!((Func<string, bool>)"".StartsWith).Method.IsAnonymous());
Debug.Assert(!((Func<string, bool>)"".StartsWith).Method.IsInner());
// Lambda
Action anonymous1 = () => { };
Debug.Assert(anonymous1.Method.IsAnonymous());
Debug.Assert(!anonymous1.Method.IsInner());
// Anonymous delegates
Action anonymous2 = delegate(){ };
Debug.Assert(anonymous2.Method.IsAnonymous());
// Sublambdas
Action anonymous3 = new Func<Func<Action>>(() => () => () => { })()();
Debug.Assert(anonymous3.Method.IsAnonymous());
void Inner() { }
Action inner1 = Inner;
Debug.Assert(inner1.Method.IsInner());
Debug.Assert(!inner1.Method.IsAnonymous());
// Deep inner methods have same tag as inner
Action Imbricated()
{
void Inside() { };
return Inside;
}
Action inner2 = Imbricated();
Debug.Assert(inner2.Method.IsInner());
}
}
Related
I'm trying to use the Convert method on functions as well as actions, so I can avoid writing duplicate methods taking in delegates of Func type. Convert method comes from Convert Action<T> to Action<object>
public class Program
{
static void Main(string[] args)
{
var program = new Program();
var mi = program.GetType().GetMethod("Function", BindingFlags.Instance | BindingFlags.Public);
// Can be any version of Func
var funcType = typeof(Func<int, int>);
// Create action delegate somehow instead
var del = mi.CreateDelegate(funcType, null);
// Or dynamically convert the Func to a corresponding Action type (in this case Action<int>)
}
// Or find a way to pass it in as a parameter here
public Action<object> Convert<T>(Action<T> action)
{
return o => action((T)o);
}
public int Function(int five)
{
return five;
}
}
I think you are looking for something like this:
public static Action<T1> IgnoreResult<T1,T2>(Func<T1,T2> func)
{
return x => func(x);
}
But for all variants of Func<T1,T2....>
I think this would work:
public static Action<TR> IgnoreResult<TR>(Delegate f)
{
return x => f.DynamicInvoke(x);
}
With usage:
var action = IgnoreResult<int>(new Func<int,int>(program.Function));
action(5);
You'll not be able to get it to infer the parameters and return type without copy and pasting the first example for all variants of Action<T1...> and Func<T1,T2...>.
I have a class with few generic overloaded methods. I am trying to get a specific one by types of its parameters. It's relatively easy to do, when I stick to the first two (with arguments of type int and string). But no matter what I do I cannot get my program to notice the third one, intended for generic list. Do I use a wrong Type argument? If so what is a correct way?
/* rest of code */
static void Main(string[] args) {
MethodInfo method =
typeof(c).GetMethod("m", new Type[] { typeof(int) });
Console.WriteLine(method);
method =
typeof(c).GetMethod("m", new Type[] { typeof(String) });
Console.WriteLine(method);
method =
typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<>) });
Console.WriteLine(method);
Console.ReadKey();
}
}
static class c
{
public static void m<T>(int i)
{
}
public static void m<T>(String s)
{
}
public static void m<T>(IEnumerable<T> Ls)
{
}
}
Short version: typeof(IEnumerable<>) is not the same as typeof(IEnumerable<T>) (for some T).
Longer version: there is no method void c.m(IEnumerable<> Ls), only overloads where the generic parameter will be some specific – existing at run time – type where the jitter has needed to create the method due to some code referencing that instantiation of the generic method.
Add a call, in your test code, to some instance of the generic method and then do a GetMethod for that instance.
Consider the following:
using System.Collections.Generic;
using System.Linq;
using static System.Console;
class Methods {
public static void M(int x) {
// no-op
}
public static void M<T>(IEnumerable<T> x) {
// no-op
}
}
class Program {
static void Main(string[] args) {
Methods.M(0);
Methods.M(new[] { "a", "b" });
ShowAllM();
}
public static void ShowAllM() {
var tm = typeof(Methods);
foreach (var mi in tm.GetMethods().Where(m => m.Name == "M"))
{
WriteLine(mi.Name);
foreach (var p in mi.GetParameters())
{
WriteLine($"\t{p.ParameterType.Name}");
}
}
}
}
which produces the output:
M
Int32
M
IEnumerable`1
Note there is only one result from the generic overload. If a call to M<char>(…) is added to Main then the output is the same.
For reflection there is just one method, are its argument reflects its "open generic" nature, but that isn't quite the same as being callable with an open generic type (eg. IEnumerable<>) as open types are not instantiatable.
(I've fudged much of the technical details here. It is instruictive to look at the difference in a debugger between typeof(IEnumerable<>) and typeof(IEnumerable<int>).)
The third method has a signature of m<T>(IEnumerable<T>) but your example shows an attempt to find a method with a signature m(IEnumerable<>).
The difference between the typeof(IEnumerable<T>) and typeof(IEnumerable<>) is the the former is a generic type and the second is a generic type definition and these are not the same thing. A generic type is determined from both the generic type definition and the generic type arguments.
With that in mind you would want to use:
method =
typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<MyType>) });
and substitute the type of enumerable that you will be passing into the method.
On the other hand if you don't know the type of enumerable up front you could get the generic method definition and make the useable generic method when you need it:
methodDef =
typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<object>) }).GetGenericMethodDefinition();
method = methodDef.MakeGenericMethod(new Type[] { typeof(MyType) });
If you remove generic defenitions from int and string methods:
public static void m(int i)
{
}
public static void m(String s)
{
}
public static void m<T>(IEnumerable<T> Ls)
{
}
And use following lines to get needed generic method:
method = typeof(c).GetMethods().FirstOrDefault(m => m.IsGenericMethod &&
m.GetParameters()[0].ParameterType.GetGenericTypeDefinition()
== typeof(IEnumerable<>));
This will do the trick
/// <summary>
/// Will fetch first occurence of IEnumerable<T> method and generate new generic method
/// <para/>
/// that corresponds to Document type
/// </summary>
/// <param name="Document"></param>
/// <param name="MethodName"></param>
/// <returns></returns>
public static MethodInfo GetAppropriateCollectionGenericMethod(object SourceClass, dynamic Document, string MethodName)
{
//get all public methods
var publicMethods = SourceClass.GetType().GetMethods().Where(x => x.Name == MethodName && x.IsGenericMethod);
//filter out only useful methods
foreach (var goodMethod in publicMethods)
{
var methodParams = goodMethod.GetParameters();
var firstParameterType = methodParams[0].ParameterType;
//methods that has arguments like Ienumerable<T>, RepeatedField<T> and so on
var hasNested = firstParameterType.GenericTypeArguments.Length > 0;
if (hasNested == true)
{
//if we found first method with that name that has as parameter an IEnumerable<T> we are ok
var genericTypeDef = firstParameterType.GetGenericTypeDefinition();
if (genericTypeDef == typeof(IEnumerable<>))
{
//Recover current document type, even if it's a list of such types
Type documentType = GetDocumentNestedType(Document);
//simply create a generic method based on Document inner Type
return goodMethod.MakeGenericMethod(documentType);
}
}
}
return null;
}
You will need this, in order to avoid errors:
var hasNested = firstParameterType.GenericTypeArguments.Length > 0;
This will fetch first occurency of:
public static void m<T>(IEnumerable<T> Ls)
{
}
and will generate a method that you can use like that:
var localMethod = GenericReflectionHelper.GetAppropriateCollectionGenericMethod(this, Document, nameof(Insert));
//we are relying on implicit casting
localMethod.Invoke(this, new object[] { Document });
Full sample:
public void Insert<T>(T Document)
{
//Valid for Lists and Repeated Fields
if (Document is IEnumerable)
{
MethodInfo localMethod;
var tuple = Tuple.Create(Document.GetType(), nameof(Insert));
if (CachedMethodsRedirection.ContainsKey(tuple) == true)
{
localMethod = CachedMethodsRedirection[tuple];
}
else
{
localMethod = GenericReflectionHelper.GetAppropriateCollectionGenericMethod(this, Document, nameof(Insert));
CachedMethodsRedirection.Add(tuple, localMethod);
}
//we are relying on implicit casting
localMethod.Invoke(this, new object[] { Document });
}
else
{
DocumentSession.GetCollection<T>().Insert(Document);
}
}
public void Insert<T>(IEnumerable<T> Document)
{
DocumentSession.GetCollection<T>().Insert(Document);
}
Please tell me what is wrong and how to write annonymous method with return for this impementation
public class Test
{
public string Implisity { get; set; }
}
class Program
{
static void Main(string[] args)
{
/*Here is a problem */
var variable = Method(delegate(IList<string> i, List<string> j){ return new Test(){Implisity = i[j.IndexOf("Implisity")]}; });
}
public static List<T> Method<T>(Func<IList<string>, IList<string>, T> staff) { return new List<T>(){staff(new List<string>() {"1","2"}, new List<string>(){"Explisity","Implisity"})}; }
}
this is a flat method what as me need to make annonymous
public static Test Annonymous(IList<string> i, List<string> j)
{
var obj = new Test() { Implisity = i[j.IndexOf("Implisity")] };
return obj;
}
The problem is that the Method(...) method expects a Func<...> with different parameter types: it expects a method that takes two IList<string> objects, while you are making a delegate that takes an IList<string> and a List<string>
var variable = Method(
delegate(IList<string> i, IList<string> j) {
// ^
return new Test() {
Implisity = i[j.IndexOf("Implisity")]
};
}
);
To avoid issues like this in the future, use implicit typing, like this:
var variable = Method( (i, j) => new Test { Implisity = i[j.IndexOf("Implisity")] } );
In this example, the compiler knows what the parameter types of the function must be from the signature of the Method(...) method, so it implicitly assigns the types to i and j.
Try this:
var variable = Method((i, j) => new Test() { Implisity = i[j.IndexOf("Implisity")] });
A lambda expression is an unnamed method written in place of a delegate instance.
The compiler immediately converts the lambda expression to either:
A delegate instance.
An expression tree, of type Expression<TDelegate>, representing the
code inside the lambda expression in a traversable object model. This
allows the lambda expression to be interpreted later at runtime
I've created a class that works with my cache to get cached items. If the items are not cached then it calls a function to get the actual value.
This class has eight methods, all with almost identical code except for the function they call. I've created a function called GetObject which takes a delegate to call if it can't find an item in the class.
I can't get my code to compile because of the following error:
Argument 2: cannot convert from
'System.Collections.Generic.List<string>' to
'MyFunction<System.Collections.Generic.List<string>>'.
Am I doing something wrong or am I'm trying to do something that can't be done?
Here's the code I'm trying.
public delegate T MyFunction<T>(string s);
public T GetCultures<T>(string s) where T : class {
return NewListOfStrings(s) as T;
}
public List<string> NewListOfStrings(string s) {
return new List<string> { s };
}
public List<string> GetListOfStrings(string sitename) {
string key = cachingService.CreateValidKey("stringvalue");
//This is the line that fails to compile
var foundItems = GetObject<List<string>>(key,
GetCultures<List<string>>(sitename));
return foundItems;
}
public T GetObject<T>(string key, MyFunction<T> f) where T : class {
T foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
lock (key) {
foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
foundItems = f as T;
if (foundItems != null) {
cachingService.SetCachedItem(key, foundItems, 5,
Constants.MINUTES);
}
}
}
}
return foundItems;
}
Solution
public T GetObject<T>(string key, Func<T> getFromRepository) where T : class {
T foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
lock (key) {
foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
foundItems = getFromRepository() as T;
if (foundItems != null) {
cachingService.SetCachedItem(key, foundItems, 5,
Constants.MINUTES);
}
}
}
}
return foundItems;
}
public AreaModels.Site GetSiteByName(string sitename) {
string key = cachingService.CreateValidKey(
string.Format("Site_{0}", sitename));
return GetObject<AreaModels.Site>(key,
() => efRepository.GetSiteByName(sitename));
}
public List<AreaModels.Culture> GetCulturesForSite(string sitename) {
string key = cachingService.CreateValidKey(
string.Format("Cultures_{0}", sitename));
return GetObject<List<AreaModels.Culture>>(key,
() => efRepository.GetCulturesForSite(sitename));
}
public List<AreaModels.Resource> Resources(string sitename, int appId) {
string key = cachingService.CreateValidKey(
string.Format("ResourcesFor{0}", sitename));
return GetObject<List<AreaModels.Resource>>(key,
() => efRepository.GetResourcesBySiteAndAppId(sitename, appId));
}
You're passing the result of the function rather than the function itself. You can use a lambda like so:
var foundItems = GetObject<List<string>>(key,
name => GetCultures<List<string>>(sitename));
You also have this line:
foundItems = f as T;
Here you're trying to cast the function itself to its return type, which won't work. Instead you could do:
foundItems = f(name);
But now your problem is that you'd have to pass the name into GetObject, because otherwise it won't be accessible where it's needed. The reason for this is there's a mismatch between MyFunction, which takes a string, and what you actually want, which is a function that can be evaluated within GetObject without needing the name parameter to be passed in.
So what you should really do is change your delegate to:
public delegate T MyFunction<T>();
Or alternatively get rid of the delegate altogether and have the f parameter be a Func<T>.
With either of these options, you can pass in the lamba with no parameter required:
var foundItems = GetObject<List<string>>(key,
() => GetCultures<List<string>>(sitename));
And evaluate it like:
foundItems = f();
Note that it's a bit roundabout to create a lambda to pass it into another method just to then evaluate it, rather than just passing the result in directly. So unless there's some reason that you need to do this in some cases, you might instead want to change the f parameter to take a type T instead. In this case I suspect you're doing it to lazily evaluate the function so that you don't have to evaluate if the result is already cached. That would probably be a valid reason, assuming you're not optimizing for performance prematurely.
You aren't creating a delegate. You are actually evaluating the method before calling GetObject. Easily fixed:
var foundItems = GetObject<List<string>>(key,
name => GetCultures<List<string>>(name));
Note also that it isn't obvious what you want to do with sitename in this scenario; you might instead mean this:
name => GetCultures<List<string>>(sitename));
Here's a complete example
public class TestDelegate
{
//You don't need generic here if you always return a list of string
public List<string> GetCulture(string s)
{
return new List<string> { s };
}
public T GetObject<T>(string key, Func<string, T> fn)
{
T foundItems = fn(key);
return foundItems;
}
public void Test()
{
List<string> test = GetObject("abc", x => GetCulture(x));
}
}
If you look at the method Test() and GetObject(), you can note 3 interesting things :
You don't have to specify the generic type on GetObject() because the compiler infer it from GetCulture()
The x parameter serves as an input to your delegate function, that way the method
GetObject can use the "key" and pass it to the delegate function.
I replace your delegate function by "Func" with a string input and a List output.
i have a method that takes as a parameter an expression because I need the method string name, and I don't care about the parameters of that method, is it possible to do that ?
I don't think that there is. You can however make a generic helper method that you can put in place of the parameters:
public T Any<T>(){
return default(T);
}
and you can call it like so:
YourMethod((YourClass yc) => yc.SomeMethod(Any<SomeClass>(), Any<SomeOtherClass>());
Yes, it's possible. Here is a concept proof test.
private static T RunExpression<T>(Expression<Func<T>> run )
{
var callExpression = (MethodCallExpression) run.Body;
var procedureName = callExpression.Method.Name;
Trace.WriteLine(procedureName);
foreach (var argument in callExpression.Arguments)
{
Trace.WriteLine(argument);
}
Trace.WriteLine(callExpression.Arguments.Count);
// Some really wicked stuff to assign out parameter
// Just for demonstration purposes
var outMember = (MemberExpression)callExpression.Arguments[1];
var e = Expression.Lambda<Func<object>>(outMember.Expression);
var o = e.Compile().Invoke();
var prop = o.GetType().GetField("s");
prop.SetValue(o, "Hello from magic method call!");
Trace.WriteLine(run.Body);
return default(T);
}
[TestMethod]
public void TestExpressionInvocation()
{
var action = new MyActionObject();
string s = null;
RunExpression(() => action.Create(1, out s));
Assert.AreEqual("Hello from magic method call!", s);
}
The easiest way to do this doesn't even use expression trees:
void Main()
{
Console.Out.WriteLine(GetNameOfMethod(new Action(Main)));
Console.Out.WriteLine(GetNameOfMethod(new Func<Delegate, string>(GetNameOfMethod)));
Console.Out.WriteLine(GetNameOfMethod(new Func<int, short, long>(AddNumber)));
Console.Out.WriteLine(GetNameOfMethod(new Action<int, short>(SwallowNumber)));
}
string GetNameOfMethod(Delegate d){
return d.Method.Name;
}
long AddNumber(int x, short y){ return x+y; }
void SwallowNumber(int x, short y){}
yields:
Main
GetNameOfMethod
AddNumber
SwallowNumber
I use this to build a BDD framework on http://storyq.codeplex.com.
Click here to see the file where I do this.
You can use this method without parameters but parentheses (even empty) are required, because without them you tell the compiler to access a property of that name.
You can use something like:
(credits go to klausbyskov)
But it's less verbose.
Also you will need to provide overloads for various argument lists.
[TestClass]
public class TestExpressions
{
public class MyClass
{
public bool MyMethod(string arg)
{
throw new NotImplementedException();
}
}
private static string UseExpression<T, Ta1>(Expression<Action<T,Ta1>> run)
{
return ((MethodCallExpression)run.Body).Method.Name;
}
[TestMethod]
public void TestExpressionParser()
{
Assert.AreEqual("MyMethod",
UseExpression<MyClass,string>((c,fakeString) => c.MyMethod(fakeString)));
}
}