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).
Related
I've a generic class like
public class Foo<T> where T : Delegate {
private T nop;
public Foo(T nop) {
this.nop = nop;
}
public T BuildDelegateChain() {
if(chainAvailable) {
return Delegate.Combine(...) as T;
} else {
return nop;
}
}
....
}
So for each instance I have to call:
Foo<Action<int>> foo = new Foo<Action<int>>( _ =>{});
Foo<Action<int,int>> foo = new Foo<Action<int,int>>( (_,__) =>{});
Is there a way to get a default "No Operation" delegate matching the type T?
I'm looking for something to replace the constructor to a constructor without any argument. Something like:
...
public Foo() {
this.nop = Delegate.CreateNop(typeof(T));
}
...
You can create a no-op delegate dynamically using the Expression class. For delegates with return types, the no-op would have to return default(TReturn). Otherwise it just needs to be an empty block. We'll then cache the delegate so reflection only happens once.
using System.Linq;
using System.Linq.Expressions;
public static class DelegateHelper<T> where T : Delegate
{
public static T NoOp { get; } = BuildNoOpDelegate();
private static T BuildNoOpDelegate()
{
var invoke = typeof(T).GetMethod(nameof(Action.Invoke));
var paramTypes = invoke.GetParameters().Select(c => c.ParameterType);
// return default(TReturn) or default(Void)
var body = Expression.Default(invoke.ReturnType);
var lambda = Expression.Lambda<T>(
body,
paramTypes.Select(Expression.Parameter)
);
return lambda.Compile();
}
}
And then to use it:
public class Foo<T> where T : Delegate {
private T nop;
public Foo() {
nop = DelegateHelper<T>.NoOp;
}
}
Interestingly, this also works for delegates with out/ref parameters. In the case of out we don't need to do anything special to set the values before the method exits (which would be required with straight C#)--they keep their default values. For example, suppose a delegate with the following signature:
public delegate int MyDelegate(out int x, ref string y);
This code will compile and execute successfully:
var nop = DelegateHelper<MyDelegate>.NoOp;
string val = "hello";
int ret = nop(out int i, ref val);
Console.WriteLine(ret); // prints "0"
Console.WriteLine(i); // prints "0"
Console.WriteLine(val); // unchanged, prints "hello"
Now this is all probably a bit overkill, but it should answer your question. Alternatively you could just treat null as your no-op sentinel value and use whatever?.Invoke() instead.
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'd like to assign a reference to a member field. But I obviously do not understand this part of C# very well, because I failed :-) So, here's my code:
public class End {
public string parameter;
public End(ref string parameter) {
this.parameter = parameter;
this.Init();
Console.WriteLine("Inside: {0}", parameter);
}
public void Init() {
this.parameter = "success";
}
}
class MainClass {
public static void Main(string[] args) {
string s = "failed";
End e = new End(ref s);
Console.WriteLine("After: {0}", s);
}
}
Output is:
Inside: failed
After: failed
How do I get "success" on the console?
Thanks in advance,
dijxtra
As others have pointed out, you cannot store a reference to a variable in a field in C#, or indeed, any CLR language.
Of course you can capture a reference to a class instance that contains a variable easily enough:
sealed class MyRef<T>
{
public T Value { get; set; }
}
public class End
{
public MyRef<string> parameter;
public End(MyRef<string> parameter)
{
this.parameter = parameter;
this.Init();
Console.WriteLine("Inside: {0}", parameter.Value);
}
public void Init()
{
this.parameter.Value = "success";
}
}
class MainClass
{
public static void Main()
{
MyRef<string> s = new MyRef<string>();
s.Value = "failed";
End e = new End(s);
Console.WriteLine("After: {0}", s.Value);
}
}
Easy peasy.
There are really two issues here.
One, as the other posters have said, you can't strictly do what you're looking to do (as you may be able to with C and the like). However - the behavior and intent are still readily workable in C# - you just have to do it the C# way.
The other issue is your unfortunate attempt to try and use strings - which are, as one of the other posters mentioned - immutable - and by definition get copied around.
So, having said that, your code can easily be converted to this, which I think does do what you want:
public class End
{
public StringBuilder parameter;
public End(StringBuilder parameter)
{
this.parameter = parameter;
this.Init();
Console.WriteLine("Inside: {0}", parameter);
}
public void Init()
{
this.parameter.Clear();
this.parameter.Append("success");
}
}
class MainClass
{
public static void Main(string[] args)
{
StringBuilder s = new StringBuilder("failed");
End e = new End(s);
Console.WriteLine("After: {0}", s);
}
}
It sounds like what you're trying to do here is make a field a reference to another storage location. Essentially having a ref field in the same way you have a ref parameter. This is not possible in C#.
One of the main issues with doing this is that in order to be verifiable the CLR (and C#) must be able to prove the object containing the field won't live longer than the location it points to. This is typically impossible as objects live on the heap and a ref can easily point into the stack. These two places have very different lifetime semantics (heap typically being longer than the stack) and hence a ref between can't be proven to be valid.
If you don't want to introduce another class like MyRef or StringBuilder because your string is already a property in an existing class you can use a Func and Action to achieve the result you are looking for.
public class End {
private readonly Func<string> getter;
private readonly Action<string> setter;
public End(Func<string> getter, Action<string> setter) {
this.getter = getter;
this.setter = setter;
this.Init();
Console.WriteLine("Inside: {0}", getter());
}
public void Init() {
setter("success");
}
}
class MainClass
{
public static void Main(string[] args)
{
string s = "failed";
End e = new End(() => s, (x) => {s = x; });
Console.WriteLine("After: {0}", s);
}
}
And if you want to simplify the calling side further (at the expense of some run-time) you can use a method like the one below to turn (some) getters into setters.
/// <summary>
/// Convert a lambda expression for a getter into a setter
/// </summary>
public static Action<T, U> GetSetter<T,U>(Expression<Func<T, U>> expression)
{
var memberExpression = (MemberExpression)expression.Body;
var property = (PropertyInfo)memberExpression.Member;
var setMethod = property.GetSetMethod();
var parameterT = Expression.Parameter(typeof(T), "x");
var parameterU = Expression.Parameter(typeof(U), "y");
var newExpression =
Expression.Lambda<Action<T, U>>(
Expression.Call(parameterT, setMethod, parameterU),
parameterT,
parameterU
);
return newExpression.Compile();
}
At this line:
this.parameter = parameter;
...you copy the method parameter to the class member parameter. Then, in Init() you are assigning the value "success", again, to the class member parameter. In your Console.Writeline, then, you are writing the value of the method parameter, "failed", because you never actually modify the method parameter.
What you are trying to do - the way you are trying to do it - is not possible, I believe in C#. I wouldn't try passing a string with the ref modifier.
As answered by JaredPar, you can't.
But the problem is partly that string is immutable. Change your parameter to be of class Basket { public string status; } and your code would basically work. No need for the ref keyword, just change parameter.status.
And the other option is of course Console.WriteLine("After: {0}", e.parameter);. Do wrap parameter in a (write-only) property.
I was wondering if there is something in c# to be able to pass a member of a class to another function that will use this member to get a value. So get a value of a field determined only which one at runtime. Something like in other languages (PHP at least I think) that you can do
a.b = "something"
but also
a["b"] = "something";
edit: actually not so good an example since a string is used, sorry
For clarity an example of what I'd like to be able to do:
class A
{
int x;
int y;
}
void somethingsomething<T>(T class, SomeMagicFieldClass f)
{
dosomethingwith(somemethodthatgivesmethevalueoffield(class, f));
}
Where then I can call the method like this:
A a = new A();
somethingsomething(a, A.x); //hypothetical notation
somethingsomething(a, A.y);
I now have something similar where I do:
somethingsomething(a, "x");
somethingsomething(a, "y");
I then go find the field using introspection API (also trying GetProperty)
MemberInfo memberInfo = item.GetType().GetField(fieldName);
This works but the disadvantage is that the fields passed as a string won't get updated when "refactoring" fieldnames in visual studio, so I was thinking maybe there exists something like this in c# that would get refactored automatically when changing field names?
Thanks a lot for reading this boring question
Your example looks a lot like a LINQ key selector, in that form it would look like:
A a = new A();
somethingsomething(a, p => p.x);
You can do some nice refactor-friendly things with LINQ Expressions. Here is a snippet of utilty code I used for such occasions. It allows you to get the Name, Type and Value of a property (it won't work with fields without modifications). There's also a setter for the value.
public static void Main(string[] args) {
var test = new { Test1 = 42, Test2 = "123", Test3 = 3.14195 };
somethingSomething(test, t => t.Test1);
somethingSomething(test, t => t.Test2);
somethingSomething(test, t => t.Test3);
}
static void somethingSomething<TObj,TProperty>(TObj obj, Expression<Func<TObj,TProperty>> expr) {
var accessor = GetMemberAccessor(expr, obj);
String name = accessor.Name;
TProperty value = accessor.Value;
String typeName = accessor.Type.Name;
Console.WriteLine("{0} = {1} ({2})", name, value, typeName);
}
The output of that would be:
Test1 = 42 (Int32)
Test2 = 123 (String)
Test3 = 3.14195 (Double)
To make this work, I used the following helper function and class:
public static MemberAccessor<TReturn> GetMemberAccessor<TObj,TReturn>(Expression<Func<TObj, TReturn>> expr, TObj tar) {
var body = expr.Body;
MemberExpression memberExpression = null;
if (body is UnaryExpression) {
var ue = (UnaryExpression)body;
memberExpression = (MemberExpression)ue.Operand;
} else if (body is MemberExpression)
memberExpression = (MemberExpression)body;
else
throw new NotImplementedException("can't get MemberExpression");
String name = memberExpression.Member.Name;
return new MemberAccessor<TReturn>(tar, name);
}
public class MemberAccessor<T> {
private readonly PropertyDescriptor propertyDesc;
private readonly Object target;
public MemberAccessor(Object target, String propertyName) {
this.target = target;
this.propertyDesc = TypeDescriptor.GetProperties(target)[propertyName];
}
public String Name {
get { return propertyDesc.Name; }
}
public Type Type {
get { return propertyDesc.PropertyType; }
}
public T Value {
get { return (T)Convert.ChangeType(propertyDesc.GetValue(target), typeof(T)); }
set { propertyDesc.SetValue(target, value); }
}
}
Mr. Plunkett is correct; a dynamic type will do the job. Luckily, the .NET 4 team included a handy object called the ExpandoObject that solves that for you.
You asked how to
pass a member of a class to another
function that will use this member to
get a value
You can usedelegates for this
class A
{
public string aField;
public string aProperty{get{return "someval";}}
public string aMemberFunction(){return "someval";}
}
void get_a_value(Func<string> func)
{
string theValue = func();
}
// use it:
A a = new A();
get_a_value( () => a.aField);
get_a_value( () => a.aProperty);
get_a_value( () => a.aMemberFunction());
What you don't get this way, of course, is a separation of parameters for the memberfunction and the object you are passing.
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)));
}
}