Why Resharper can't tell initialization is used - c#

I am writing unit-tests while I've stumbled upon following suggestion by Resharper.
Value assigned is not used by any execution path.
in the following code snipet.
[Test]
[TestCase((int)OddsRoundingModes.Floor)]
public void GetBaseOddsRoundingMode_WithCorrectRoundingMode_ShouldReturnCorrectRoundingMode(int oddsRoundingMode)
{
// Arrange
var oddsRoundingModeStr = oddsRoundingMode.ToString(); // <-- suggestion here
var mock = new Mock<IConstantsStorage>();
var oddsRoundingConfiguration = new OddsRoundingConfiguration(mock.Object);
mock.Setup(h => h.TryGetConstant(It.IsAny<string>(), It.IsAny<int>(), out oddsRoundingModeStr))
.Returns(true);
// Act
var roundingMode = oddsRoundingConfiguration.GetBaseOddsRoundingMode(0);
// Assert
Assert.AreNotEqual(roundingMode, OddsRoundingModes.None);
}
But then when I change this to be not initialized at declaration, the mock is not properly setup and test fails, because oddsRoundingModeStr is not initialized and the mock return it as null.
Why can't Resharper see this?
EDIT:
public bool TryGetConstant(string name, int siteId, out string value)
{
value = RetrieveConstant(_constantsModel, name, siteId);
return value != null;
}
private string RetrieveConstant<T>(IConstantsModel<T> model, string constName, int siteId)
where T : IConstant, new()
{
if (model.Constants.TryGetValue(constName, out List<T> values))
{
var constant = values.FirstOrDefault(v => v.Name == constName && v.SiteIds.Contains(siteId));
if (constant != null)
{
return constant.ConstantValue;
}
}
return null;
}

Following normal C# semantics the value you initialize that variable to is irrelevant, since out can't read the data before having assigned a new value to it. Thus the resharper notice is appropriate.
I see several ways non standard semantics could be achieved using this code:
out is a decorated ref at the CLR level. So low level code could treat it as equivalent to ref.
void Main()
{
Ref r = R;
Out o = (Out)Delegate.CreateDelegate(typeof(Out), null, r.Method);
int i = 2;
o(out i);
i.Dump();
}
delegate void Out(out int x);
delegate void Ref(ref int x);
void R(ref int x)
{
x++;
}
Setup takes delegate and then uses private reflection on the closure object.
Setup takes an Expression<T>, i.e. a syntax tree of the lambda and interprets the expression in non standard ways.
In this context, the lambda expression is not C# code intended to be executed, but essentially a DSL describing how to setup the mock.
Option 3 seems the most likely

Setup accepts expression tree - and Moq analyzes that expression tree to create a moq. In this case you are basically saying that Moq should create implementation of IConstantsModel which accepts any string, any int, returns true and returns value you provide in oddsRoundingModeStr as out parameter. So when analyzing this expression tree, Moq will extract actual value of oddsRoundingModeStr (which is captured and stored in a field of compiler-generated class) and indeed will use it. Resharper is just unable to realize this, so provides a warning as usual.
Small example of how out variable value can be extracted from expression tree:
class Program {
static void Main(string[] args) {
int result = 2; // gives warning from your question
var back = ExtractOutValue(s => int.TryParse(s, out result));
Debug.Assert(back == result);
}
static int ExtractOutValue(Expression<Action<string>> exp) {
var call = (MethodCallExpression)exp.Body;
var arg = (MemberExpression) call.Arguments[1];
return (int) ((FieldInfo)arg.Member).GetValue(((ConstantExpression)arg.Expression).Value);
}
}

Related

Why do I have to type-cast a strongly typed function using a dynamic input-parameter?

I have a converter method:
MyPoco Convert(dynamic p) => new MyPoco { A = p.X, B = p.Y };
void Test()
{
dynamic item = new { X = 1, Y = 2 };
var poco = (MyPoco)Convert(item);
}
I have to explictly cast the result to MyPoco, otherwise poco will become a dynamic variable, too.
But, if I inline the Convert method;
void Test()
{
MyPoco Convert(dynamic p) => new MyPoco { A = p.X, B = p.Y };
dynamic item = new { X = 1, Y = 2 };
var poco = Convert(item);
}
I don't need to cast ConvertItem to MyPoco. Is there a reason for this behavior? It should be easy for the compiler to know that Convert return-type is MyPoco, right?
There is a difference between them which could be the reason - local functions don't support overloading. I think it is important - imagine we have two methods with the same name and with different input and output types
static void Main(string[] args)
{
dynamic d = null;
var result = Hello(d);
Console.WriteLine("Hello World!");
}
static string Hello(string s)
{
return s;
}
static int Hello(int i)
{
return i;
}
It means the result may be string or int - we don't know it in compile time.
While for the following code we get the error that local variable or function already declared
static void Main(string[] args)
{
string Hello(string s)
{
return s;
}
int Hello(int s) // error - local variable or function with the same name already declared
{
return s;
}
dynamic d = null;
var result = Hello(d);
Console.WriteLine("Hello World!");
}
We can only write something like this
static void Main(string[] args)
{
string Hello(string s)
{
return s;
}
dynamic d = null;
var result = Hello(d);
Console.WriteLine("Hello World!");
}
So when compiler sees the local Hello(...) call it knows that return type is string.
Upd:
Regarding the compiler ability to infer correct type in case of dynamic.
I think yes, it is possible for compiler to catch such cases - if we know in compile time that there is the only one method,
there is no chance that in runtime another one will appear.
I could imagine e.g. the method we call is in another assembly, and in runtime we loaded newer version which has different signature - with dynamic it will work, but for the, say, private static method with no overloads I think we could infer non-dynamic type.
But I think, it is was decided to implement it that way for the sake of simplicity - it is easier to keep in mind simple rule - everything that touches dynamic - dynamic.
For local functions for simplicity I think it would be easier to also have them dynamic. I think it is just decision made by different people implementing that.
I checked the roslyn source code trying to find information about that.
The place where it is defined is Binder_Invocation.cs, BindMethodGroupInvocation method.
For local function the following method is called
private BoundExpression BindLocalFunctionInvocationWithDynamicArgument(
SyntaxNode syntax,
SyntaxNode expression,
string methodName,
BoundMethodGroup boundMethodGroup,
DiagnosticBag diagnostics,
CSharpSyntaxNode queryClause,
MethodGroupResolution resolution)
{
// Invocations of local functions with dynamic arguments don't need
// to be dispatched as dynamic invocations since they cannot be
// overloaded. Instead, we'll just emit a standard call with
// dynamic implicit conversions for any dynamic arguments. There
// are two exceptions: "params", and unconstructed generics. While
// implementing those cases with dynamic invocations is possible,
// we have decided the implementation complexity is not worth it.
// Refer to the comments below for the exact semantics.
As you can see the also say about overloading, but for the normal method call no any information about the reason
else
{
if (HasApplicableConditionalMethod(resolution.OverloadResolutionResult))
{
// warning CS1974: The dynamically dispatched call to method 'Goo' may fail at runtime
// because one or more applicable overloads are conditional methods
Error(diagnostics, ErrorCode.WRN_DynamicDispatchToConditionalMethod, syntax, methodGroup.Name);
}
// Note that the runtime binder may consider candidates that haven't passed compile-time final validation
// and an ambiguity error may be reported. Also additional checks are performed in runtime final validation
// that are not performed at compile-time.
// Only if the set of final applicable candidates is empty we know for sure the call will fail at runtime.
var finalApplicableCandidates = GetCandidatesPassingFinalValidation(syntax, resolution.OverloadResolutionResult,
methodGroup.ReceiverOpt,
methodGroup.TypeArgumentsOpt,
diagnostics);
if (finalApplicableCandidates.Length > 0)
{
result = BindDynamicInvocation(syntax, methodGroup, resolution.AnalyzedArguments, finalApplicableCandidates, diagnostics, queryClause);
}
else
{
result = CreateBadCall(syntax, methodGroup, methodGroup.ResultKind, analyzedArguments);
}
They create dynamic if there is at least one canditate.
So, as I said, I think it could be done non-dynamic, but the people who implemented it originally kept it dynamic, probably for simplicity.
What you could do in order to find more details is to try to implement the case when no overloading methods, changing the code
if (finalApplicableCandidates.Length > 0)
{
result = BindDynamicInvocation(syntax, methodGroup, resolution.AnalyzedArguments, finalApplicableCandidates, diagnostics, queryClause);
}
by adding the check if Length == 1 then call BindInvocationExpressionContinued instead of BindDynamicInvocation
and run the tests and check if something fails, maybe it helps.(I didn't even manage to get the roslyn project built, dotnet core is a bit weird)
P.S.
According to this
if (boundMethodGroup.TypeArgumentsOpt.IsDefaultOrEmpty && localFunction.IsGenericMethod)
{
Error(diagnostics, ErrorCode.ERR_DynamicLocalFunctionTypeParameter, syntax, localFunction.Name);
return BindDynamicInvocation(
For local function we could get dynamic instead of concrete type.
If you type something like this
static void Main(string[] args)
{
int TestFunc<T>(T data)
{
return 1;
}
dynamic d = 2;
var r = TestFunc(d);
}
Yes, it will give the error, but if you check the inferred type it of r will show dynamic))

Clever way to add two objects

I'm trying to make some method like below.
It just add two given objects and return.
object add(object a, object b);
I already tried it with dynamic keyword. Unfortunately this one does not work on iOS. (the platform does not allow runtime code generations)
dynamic add(dynamic a, dynamic b) => a + b;
So, here's my second try and I realized that it's gonna be hell with this way.
private static HybInstance Add(HybInstance a, HybInstance b)
{
if (a.Is<Int32>()) return AddInt32(a, b);
/* and so on... */
}
private static HybInstance AddInt32(HybInstance a, HybInstance b)
{
Int32 ia = a.As<Int32>();
if (b.Is<Int16>()) return HybInstance.Int(ia + b.As<Int32>());
if (b.Is<Int32>()) return HybInstance.Int(ia + b.As<Int32>());
if (b.Is<Int64>()) return HybInstance.Int64(ia + b.As<Int64>());
if (b.Is<float>()) return HybInstance.Float(ia + b.As<float>());
throw new SemanticViolationException($"");
}
// the method should support custom operators too
private static MethodInfo GetAddMethod(HybInstance left) {
return left.GetMethods("op_Addition").FirstOrDefault();
}
Is there any smarter way to add two objects?
addition:
Here are some examples what I want to do.
Just add any kind of objects or throw exception if not possible.
add(1, 1); // 2
add(1, "b"); // exception
add("a", "b"); // "ab"
// and this one also should be work
add(some_class_with_operator_overloading, 10);
Closest you could get using standard .NET types is probably IConvertible:
static IConvertible Add (IConvertible a, IConvertible b)
{
if (a is string) return a.ToString() + b;
if (b is string) return a + b.ToString();
// other special cases here
return a.ToDouble(CultureInfo.CurrentCulture) + b.ToDouble(CultureInfo.CurrentCulture);
}
static void Main(string[] args)
{
IConvertible a = 1;
IConvertible b = 2;
IConvertible s = "string";
Console.WriteLine(Add(a, b));
Console.WriteLine(Add(s, s));
Console.WriteLine(Add(a, s));
}
Produces
3
stringstring
1string
It's impossible to add two objects, because there's nothing about objects that can be added.
It's like you would like add "something" to "something" and expected someone to answer your question with precise answer - it's impossible.
object don't have any fields or properties, so how you'd like to add them??
Unless you have in mind some kind of general rule of adding objects based on their real type, then it would become possible: you would have to check the type of input parameters and then in (rather) huge switch statement return appropriate result (eg. concatenation for strings, simple addition for integers...).
Did you try with generics, 2 things though:
You are wrapping different objects in same wrapper, seems like a design issue, but will leave it since I do not know more.
Most of the int can be directly changed to Int64 and then there will not be that many special cases
I would have a generic function, and would pass it the Add/Combine function which can be defined for different types. Seems to be a cleaner approach.
public T Add<T1, T2, T>(T1 firstObject, T2 secondObject, Func<T1,T2,T>Combine)
{
var result = Combine(firstObject, secondObject);
return result;
}
Update
Seems like this will not work either
Limitations of Xamarin.iOS
No Dynamic Code Generation
Since the iOS kernel prevents an application from generating code dynamically, Xamarin.iOS does not support any form of dynamic code generation. These include:
The System.Reflection.Emit is not available.
No support for System.Runtime.Remoting.
No support for creating types dynamically (no Type.GetType ("MyType`1")), although looking up existing types (Type.GetType ("System.String") for example, works just fine).
Reverse callbacks must be registered with the runtime at compile ti
However
Why does LambdaExpression.Compile() work on iOS (Xamarin)?
On platforms that support code generation, Reflection.Emit-based
LambdaCompiler
is used.
If that's not available, the expression is interpreted using the
interpreter
For example, there are classes that interpret Constant and Add.
Original
I am not sure how much mileage you could get out of this, but you could use expressions
public static object Add<T,T2>(T a,T2 b)
{
var paramA = Expression.Parameter(typeof(T), "a");
var paramB = Expression.Parameter(typeof(T2), "b");
var body = Expression.Add(Expression.Convert(paramA, paramB.Type), paramB);
var add = Expression.Lambda<Func<T, T2, T2>>(body, paramA, paramB).Compile();
return add(a, b);
}
The assumptions it that it will try to convert to the second parameter type and return of that type.
Obviously you any class will need the appropriate operators
Given
public struct Test
{
// user-defined conversion from Fraction to double
public static implicit operator int(Test f)
{
return 10;
}
public static implicit operator Test(int i)
{
return new Test();
}
// overload operator *
public static Test operator +(Test a, Test b)
{
return new Test();
}
}
Example
Console.WriteLine(Add(1, 2));
Console.WriteLine(Add(1, 2.0));
Console.WriteLine(Add(1, new Test()));
Refelction can be used to walk the properties of both objects, check for name equivalency and numeric data type, then amend property values in a totally generic way:
public static void AddObjects(object oFrom, object oTo)
{
if (oFrom != null && oTo != null)
{
foreach (System.Reflection.PropertyInfo f in oFrom.GetType().GetProperties())
{
if ((oTo).GetType().GetProperty(f.Name) != null)
{
try
{
string sType = f.GetType().ToString().ToLower();
if (sType==("int") )
{
oFrom.GetType().GetProperty(f.Name).SetValue(oFrom, (int)(f.GetValue(oFrom)) + (int)(f.GetValue(oTo)));
}
if (sType=="int32" )
{
oFrom.GetType().GetProperty(f.Name).SetValue(oFrom, (Int32)(f.GetValue(oFrom)) + (Int32)(f.GetValue(oTo)));
}
if (sType==("int64") )
{
oFrom.GetType().GetProperty(f.Name).SetValue(oFrom, (Int64)(f.GetValue(oFrom)) + (Int64)(f.GetValue(oTo)));
}
// keep adding for all numeirc types. maybe theres a better way?
}
catch (Exception ex)
{ }
}
}
}
}

What is the difference between Expression.Variable() and Expression.Parameter()?

Both seem to return the same type, and have the same signature.
So what is the difference between them, and when should we use each?
Expression.Variable is used to declare a local variable within a block. Expression.Parameter is used to declare a parameter for an incoming value.
Now currently C# doesn't allow statement-bodied lambda expressions, but if it did, imagine:
// Not currently valid, admittedly...
Expression<Func<int, int>> foo = x =>
{
int y = DateTime.Now.Hour;
return x + y;
};
If this were valid, the C# compiler would generate code using Expression.Parameter for x, and Expression.Variable for y.
At least, that's my understanding. It's a real shame that the documentation for the two methods is basically the same :(
Effectively, there is no difference, apart from the fact that Variable() does not allow ref types. To see that, you can look at the reference source:
public static ParameterExpression Parameter(Type type, string name) {
ContractUtils.RequiresNotNull(type, "type");
if (type == typeof(void)) {
throw Error.ArgumentCannotBeOfTypeVoid();
}
bool byref = type.IsByRef;
if (byref) {
type = type.GetElementType();
}
return ParameterExpression.Make(type, name, byref);
}
public static ParameterExpression Variable(Type type, string name) {
ContractUtils.RequiresNotNull(type, "type");
if (type == typeof(void)) throw Error.ArgumentCannotBeOfTypeVoid();
if (type.IsByRef) throw Error.TypeMustNotBeByRef();
return ParameterExpression.Make(type, name, false);
}
As you can see, both methods call ParameterExpression.Make(), so the returned object will behave the same.

Create a variable of a type only known at runtime (C#)

My question is very similar to : Cast to type known only at runtime , however that one was not really answered (it's also in C rather than C#).
I'm writing something to control some hardware, and depending on the given hardware configuration I have to do some bitwise arithmetic with a "byte" or "UInt32" type. The bit arithmetic code is long but identical in the 32bit and 8bit case, with the only difference being the length of certain loops (32 or 8).
My current solution is to use a switch, which means I have pretty much two copies of the same code in a giant if statement.
An alternative solution is to use an array or 0s and 1s rather than a UInt32 or byte to do the bitwise operations and then convert to UInt32 or byte at the end.
The last solution, which I'm most interested in here, is to dynamically pick which type I will use at runtime. Here is some pseudocode for what I would like:
System.Type MyType;
if (something)
MyType=type1;
else
MyType=somethingElse;
myType someVariable; //Create a variable of type myType. This line will give an
//error
someVariable=(myType) otherVariable //do an example typecast with the
//runtime-determined type
I've searched around to know that the answer may have something to do with generics and reflection, but I can't figure out how to do it exactly.
You might consider using a BitArray for this - you can initialise it from a byte or uint32, do the bitwise operations, and then convert it back at the end e.g.
object value;
bool isByte = value is byte;
BitArray ba = isByte
? new BitArray(new byte[] { (byte)value })
: new BitArray(BitConverter.GetBytes((unint32)value));
...
I would probably create an abstract class, something like HardwareConfigBase which includes your looping code as well as the size of the loop. Then have 2 child classes that extend that base class.
public abstract class HardwareConfigBase
{
protected int TimesToLoop;
public byte[] Data = new byte[32 * 8]; //Size of UInt, but still works for 8bit byte
public void MyLoopCode
{
for(int i = 0; i < TimesToLoop; i++)
{
//Do whatever
}
}
}
public class ByteHardwareConfig
{
public ByteHardwareConfig
{
TimesToLoop = 8;
}
}
public class UIntHardwareConfig
{
public UIntHardwareConfig
{
TimesToLoop = 32;
}
}
public void Main()
{
var myHardwareConfig = new ByteHardwareConfig(); //Could also be UInt
//Do some more initialization and fill the Data property.
myHardwareConfig.MyLoopCode();
}
You can create an instance of a type at runtime using Activator.CreateInstance() like so:
object myInstance = Activator.CreateInstance(MyType);
Then, see this question for how to do a type cast at runtime using only runtime-known types.
public static dynamic Convert(dynamic source, Type dest) {
return Convert.ChangeType(source, dest);
}
myInstance = Convert(myInstance, MyType);
// will result in myInstance being of type MyType.
The answer is rather pretty simple. You will not need to cast or convert any variables at runtime in order to be able to modify uint or byte types at runtime. The following three definitions will suffice.
The first class definition is the Provider class which defines two methods, each one to modify either a variable of uint or byte type. Be sure to put your modifying logic inside the methods.
class Provider
{
public uint GetResult(uint c)
{
return c;
}
public byte GetResult(byte c)
{
return c;
}
}
The next class is the one that will invoke the appropriate method from the previous class definition, depending on the type of the parameter you provide.
class Execute
{
public object GetResult(object source)
{
var provider = new Provider();
return provider.GetType()
.GetMethods()
.Where(x => x.Name == "GetResult" && x.ReturnType == source.GetType())
.First()
.Invoke(provider, new object[] { source });
}
}
The last definition is here to simply test how this setup works. You can see that we have both a byte and a uint type. Passing them both to the GetResult(object) method yields the expected results, and as you can see, the underlying system type is also as expected.
class Program
{
static void Main()
{
uint u = 1;
byte b = 2;
var result1 = new Execute().GetResult(u);
var result2 = new Execute().GetResult(b);
sc.WriteLine(result1 + " " + result1.GetType().UnderlyingSystemType);
sc.WriteLine(result2 + " " + result2.GetType().UnderlyingSystemType);
sc.Read();
}
}
Try using the dynamic keyword in C#.
dynamic myType;
if (a) {
myType = new type1();
} else {
myType = new type2();
}

delegate keyword vs. lambda notation

Once it is compiled, is there a difference between:
delegate { x = 0; }
and
() => { x = 0 }
?
Short answer : no.
Longer answer that may not be relevant:
If you assign the lambda to a delegate type (such as Func or Action) you'll get an anonymous delegate.
If you assign the lambda to an Expression type, you'll get an expression tree instead of a anonymous delegate. The expression tree can then be compiled to an anonymous delegate.
Edit:
Here's some links for Expressions.
System.Linq.Expression.Expression(TDelegate) (start here).
Linq in-memory with delegates (such as System.Func) uses System.Linq.Enumerable. Linq to SQL (and anything else) with expressions uses System.Linq.Queryable. Check out the parameters on those methods.
An Explanation from ScottGu. In a nutshell, Linq in-memory will produce some anonymous methods to resolve your query. Linq to SQL will produce an expression tree that represents the query and then translate that tree into T-SQL. Linq to Entities will produce an expression tree that represents the query and then translate that tree into platform appropriate SQL.
I like Amy's answer, but I thought I'd be pedantic. The question says, "Once it is compiled" - which suggests that both expressions have been compiled. How could they both compile, but with one being converted to a delegate and one to an expression tree? It's a tricky one - you have to use another feature of anonymous methods; the only one which isn't shared by lambda expressions. If you specify an anonymous method without specifying a parameter list at all it is compatible with any delegate type returning void and without any out parameters. Armed with this knowledge, we should be able to construct two overloads to make the expressions completely unambiguous but very different.
But disaster strikes! At least with C# 3.0, you can't convert a lambda expression with a block body into an expression - nor can you convert a lambda expression with an assignment in the body (even if it is used as the return value). This may change with C# 4.0 and .NET 4.0, which allow more to be expressed in an expression tree. So in other words, with the examples MojoFilter happened to give, the two will almost always be converted to the same thing. (More details in a minute.)
We can use the delegate parameters trick if we change the bodies a little bit though:
using System;
using System.Linq.Expressions;
public class Test
{
static void Main()
{
int x = 0;
Foo( () => x );
Foo( delegate { return x; } );
}
static void Foo(Func<int, int> action)
{
Console.WriteLine("I suspect the anonymous method...");
}
static void Foo(Expression<Func<int>> func)
{
Console.WriteLine("I suspect the lambda expression...");
}
}
But wait! We can differentiate between the two even without using expression trees, if we're cunning enough. The example below uses the overload resolution rules (and the anonymous delegate matching trick)...
using System;
using System.Linq.Expressions;
public class Base
{
public void Foo(Action action)
{
Console.WriteLine("I suspect the lambda expression...");
}
}
public class Derived : Base
{
public void Foo(Action<int> action)
{
Console.WriteLine("I suspect the anonymous method...");
}
}
class Test
{
static void Main()
{
Derived d = new Derived();
int x = 0;
d.Foo( () => { x = 0; } );
d.Foo( delegate { x = 0; } );
}
}
Ouch. Remember kids, every time you overload a method inherited from a base class, a little kitten starts crying.
In the two examples above there's no difference, zero.
The expression:
() => { x = 0 }
is a Lambda expression with statement body, so it can't be compiled as an expression tree. In fact it doesn't even compile because it needs a semicolon after 0:
() => { x = 0; } // Lambda statement body
() => x = 0 // Lambda expression body, could be an expression tree.
Amy B is correct. Note that there can be advantages to using expression trees. LINQ to SQL will examine the expression tree and convert it to SQL.
You can also play tricks with lamdas and expression trees to effectively pass the names of class members to a framework in a refactoring-safe way. Moq is an example of this.
There is a difference
Example:
var mytask = Task.Factory.StartNew(() =>
{
Thread.Sleep(5000);
return 2712;
});
mytask.ContinueWith(delegate
{
_backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});
And I replace with lambda:(error)
var mytask = Task.Factory.StartNew(() =>
{
Thread.Sleep(5000);
return 2712;
});
mytask.ContinueWith(()=>
{
_backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});
Some basics here.
This is a anonymous method
(string testString) => { Console.WriteLine(testString); };
As anonymous methods do not have names we need a delegate in which we can assign both of these methods or expressions. e.g.
delegate void PrintTestString(string testString); // declare a delegate
PrintTestString print = (string testString) => { Console.WriteLine(testString); };
print();
Same with the lambda expression. Usually we need a delegate to use them
s => s.Age > someValue && s.Age < someValue // will return true/false
We can use a func delegate to use this expression.
Func< Student,bool> checkStudentAge = s => s.Age > someValue && s.Age < someValue ;
bool result = checkStudentAge ( Student Object);

Categories

Resources