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
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'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.
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());
}
}
I am working on a generic utility method that takes a generic argument and returns a generic type--I hope that makes sense!--but I want the return type to be a different type from the argument.
Here's what I'm thinking this should look like if I mock it up in pseudo code:
public static IEnumerable<R> DoSomethingAwesome<T>(T thing)
{
var results = new List<R>();
for (int xx = 0; xx < 5; xx++)
{
results.Add(thing.ToRType(xx));
}
return results;
}
With generics not being able to infer the return type how would I go about doing something like this? So far, my Google-Fu has failed me.
// You need this to constrain T in your method and call ToRType()
public interface IConvertableToTReturn
{
object ToRType(int someInt);
}
public static IEnumerable<TReturn> DoSomethingAwesome<T, TReturn>(T thing)
where T : IConvertableToTReturn
{
Enumerable.Range(0, 5).Select(xx => thing.ToRType(xx));
}
You can pass the return class as an output parameter:
public static void DoSomethingAwesome<T,R>(T thing, out IEnumerable<R> output)
This can then be inferred.
static IEnumerable<R> Function<T,R> (T h)
{
for (int xx = 0; xx < 5; xx++)
{
yield return h.ToRType(xx);
}
yield return break;
}
IEnumerable<class2> res = Function<class1, class2>(class1Object);
You need to explicitly specify the return generic type as a type parameter to the method.
Something like:
public static IEnumerable<R> DoSomething<T,R>(IEnumerable<T> things, Func<T,R> map)
{
foreach (var t in things) { yield return map(t); }
}
This is essentially what the Linq IEnumerable extension method "Select" does..
Generics can be awesome and a pretty awesome pain. As other have stated you can use a variety of ways to have multiple in put parameters the real trick is in doing something usefully with the passed in types.
in Your example
public static IEnumerable<Ret> Fn<Ret,Parm>(IList<Parm> P)
{
var Results = new List<Ret>();
foreach(Parm p in P)
{
Results.Add(p.ToType());
}
return Results;
}
Will not complie since the complier doesn't know what to do with P.ToType()
So you say well I can just add the function needed to my param type But that doesn't work either since the complier again doesn't know what the concrete version or Ret will be and your return list is of type Ret not of type returnType
public class RetunType
{
public int a;
}
public class Input
{
public int x;
public RetunType TotoAReturnType()
{
return new RetunType() { a = this.x };
}
}
public static IEnumerable<Ret> Fn<Ret, Parm>(IList<Parm> P) where Parm : Input where Ret:RetunType
{
var Results = new List<Ret>();
foreach (Parm p in P)
{
Results.Add(p.TotoAReturnType());
}
return Results;
}
To solve this issue you can add a generic interface so that your function can work if any type supports the generic interface
Like this
public interface ToType<R>
{
R ToType();
}
public class B
{
public int x;
}
public class A : ToType<B>
{
string x = "5";
public B ToType()
{
B aB = new B();
aB.x = int.Parse(x);
return aB;
}
}
public static IEnumerable<Ret> Fn<Ret,Parm>(IList<Parm> P) where Parm : ToType<Ret>
{
var Results = new List<Ret>();
foreach(Parm p in P)
{
Results.Add(p.ToType());
}
return Results;
}
static void Main(string[] args)
{
List<A> inLst = new List<A>() { new A()};
var lst = Fn<B, A>(inLst);
}
Generics are awesome but I would strongly suggest looking to using interfaces to support you actions in those functions.
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)));
}
}