Can a delegate take a generic as a parameter - c#

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.

Related

Using lambda on a method with out parameter as a boolean

I'm trying to pass a method that returns a string with an out parameter as a boolean. based on if the method that returns the string, returns the same string.
Barebone sample code that doesn't work because the lambda is invalid:
class Class1 {
void Foo () {
s = "some value";
if (() => { (Class2.Foo(s, out s)); })
return; // Do stuff here
}
}
public static class Class2 {
string Foo(string s, out string _s) {
bool ok = true; // HACK
_s = "";
return ok ? _s : s;
}
}
How, if possible, can I make this work properly by only changing/replacing the lambda expression?
Edit: Seems like I've been asking this a bit backwards and silly. Here is more generalized version on what I'm trying to accomplish:
I want to send a method an object of any type, and get either the same object back, or a new one if the function succeeded. I then want to use the method itself as a boolean, so code within the if statement only runs if I get a new object back.
I realize that this is an odd way to do this, but there is method behind this nonsense (at least in my head).
You can't compare values against a lambda expression directly. What you can do is wrap the lambda in a Func and check the result:
if (new Func<string>(() => Class2.Foo(s, out s)).Invoke() == "some value")
{
// Do stuff
}
It isn't clear from your code exactly why you are using a lambda at all, though. If possible, you should instead just call the method:
if (Class2.Foo(s, out s) == "some value")
{
// Do stuff
}
Per the clarification in the comments, I think it would be better to do one of two things. Either A] have only one ref parameter and do the assignment in the method (assisted for cleanliness with generics):
class Class1
{
void Foo ()
{
s = "some value";
sa = "some other value";
if (Class2.Foo(ref s, sa))
{
// Do stuff here
}
}
}
public static class Class2
{
public static bool Foo<T>(ref T o, T alt) {
bool ok = // Do some function
if (ok)
o = alt;
return ok;
}
}
or B] just get the correct object back from the method:
class Class1
{
void Foo ()
{
sa = "some value";
sb = "some other value";
r = Class2.Foo(sa, sb);
if (r != sa)
{
// Do stuff here
}
}
}
public static class Class2
{
public static T Foo<T>(T a, T b)
{
bool ok = // Do some function
if (ok)
return a;
return b;
}
}
It's still not clear why you need a lambda, but if you do, you can simply wrap it in a Func (as per my above answer) or in a Predicate (as per Mrinal Kamboj's answer).

Anonymous method with return

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

Determine if MethodInfo represents a lambda expression

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());
}
}

Function with variable arguments as parameter to another function

How can I define a function that expects another function that returns a bool in c#?
To clarify, this is what I'd like to do using C++:
void Execute(boost::function<int(void)> fctn)
{
if(fctn() != 0)
{
show_error();
}
}
int doSomething(int);
int doSomethingElse(int, string);
int main(int argc, char *argv[])
{
Execute(boost::bind(&doSomething, 12));
Execute(boost::bind(&doSomethingElse, 12, "Hello"));
}
In my example above the Execute function in combination is with the bind gets the expected result.
Background:
I've got a bunch of functions, each returning a int but with different parameter count that are surrounded by the same error checking code. A huge code duplication I want to avoid...
You can probably achieve what you want by using Func. For example
void Execute(Func<bool> myFunc)
{
if(myFunc() == false)
{
// Show error
}
}
You can then define your Func either as a method, or a lambda:
// Define a method
private bool MethodFunc() {}
// Pass in the method
Execute(MethodFunc)
// Pass in the Lambda
Execute(() => { return true; });
You don't nececssairly need to pass the parameters in as you can now access them from the caller's scope:
Execute(() => { return myBool; });
Execute(() => { return String.IsNullOrEmpty(myStr); });
With my solution, you can perform any function, any input parameter, with any return, this is a very generic implementation
Example:
public T YourMethod<T>(Func<T> functionParam)
{
return functionParam.Invoke();
}
public bool YourFunction(string foo, string bar, int intTest)
{
return true;
}
Call like This specifying the return :
YourMethod<bool>(() => YourFunction("bar", "foo", 1));
Or like this:
YourMethod(() => YourFunction("bar", "foo", 1));
without argument do this
void Execute(Func<bool> fctn)
{
if(fctn() )
{
show_error();
}
}
with arguments you can do something like this:
void Execute<T>(Func<T[],bool> fctn)
{
var v = new T[4];
if(fctn(v) )
{
show_error();
}
}

o => o.MethodWithParameters | is it possible to use a method in a lambda without () and parameters

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)));
}
}

Categories