pass a bool expression as a method parameter - c#

i am a bit confused trying to implement a more elegant generic solution using lambda/LINQ Expression or Func<bool> to simply replace a bool return type.
say the expression is:
public bool someBoolRetMethod(someType parA, someOtherType parB) {
if(parA==null)
return new ExpM("relevant msg").Rtrn;
}
so now if parA is null, ExpM() is a class that deals with errors
what i wanted to do is pass the condition as a parameter :
public class ExpBoolCond:ExpM {
public bool Rtrn{get;set;}
public ExpBoolCond(theBool, themsg) {
variable to hold theBool;
if(theBool) new specialMbxWindow(themsg)
then set Rtrn..
}
}
so in that way i could use:
var condNullParA = new ExpBoolCond(parA==null, "passed ParA is Null,\r\nAborting method <sub>(methodName and line# is handled inside ExpM base class)</sub> !")
if(condNullParA.Rtrn) ....
what is the correct way to implement it ?
Update :
public class ExcBCondM:ExcpM
{
public bool Rtrn { get { return this._Rtrn(); } }
Func<bool> _Rtrn { get; set; }
public ExcBCondM(Func<bool> cond, string bsMsg)
: base(bsMsg,false)
{
this._Rtrn = cond;
//if (this._Rtrn) this.show();
}
public bool activateNon() { this.show(); return false; }
}
usage:
public bool someBoolRetMethod(some_passed_Type parA)
{
var someCondExpM = new ExpBoolCond(() => parA==null, "relevant Message");
if(someCondExpM.Rtrn)
return someCondExpM.activateNon(); //if() now Calls Func<bool> _Rtrn when called rather where stated.
return true;//if ok...
}

If you want to create Func<bool> as a lambda expression, the syntax is as follows:
var condNullParA = new ExpBoolCond(() => parA==null, "passed ParA is Null,\r\nAborting method <sub>(methodName and line# is handled inside ExpM base class)</sub> !")
// ^^^^^
The () => part tells C# compiler that the expression that follows should become a body of a lambda that takes no parameters, and returns whatever is the type of the expression to the right of the => sign, i.e. a bool.

Related

How to create a generic method to iterate through an object's fields and use it as a Where predicate?

I'm building a generic interface to expose selected string properties out of a class, and then I want to search for a text inside every one of those fields, to check if it's a match.
Here's my IFieldExposer interface:
using System;
using System.Collections.Generic;
public interface IFieldExposer<T>
{
IEnumerable<Func<T, string>> GetFields();
}
Now, I implement it like this in my DataClass to expose the properties I would like to iterate. Note that I'm also exposing a property from my ChildClass:
using System;
using System.Collections.Generic;
class DataClass : IFieldExposer<DataClass>
{
public string PropertyOne { get; set; }
public string PropertyTwo { get; set; }
public ChildClass Child { get; set; }
public IEnumerable<Func<DataClass, string>> GetFields()
{
return new List<Func<DataClass, string>>
{
a => a.PropertyOne,
b => b.Child.PropertyThree
};
}
}
class ChildClass
{
public string PropertyThree { get; set; }
}
I've also created extension methods for IFieldExposer<T> because I want to keep it simple and be able to simply call obj.Match(text, ignoreCase) everywhere else in my code. This method should tell me if my object is a match for my text. Here's the code for the ExtensionClass, which isn't working as expected:
using System;
using System.Linq.Expressions;
using System.Reflection;
public static class ExtensionClass
{
public static bool Match<T>(this IFieldExposer<T> obj, string text, bool ignoreCase)
{
Func<bool> expression = Expression.Lambda<Func<bool>>(obj.CreateExpressionTree(text, ignoreCase)).Compile();
return expression();
}
private static Expression CreateExpressionTree<T>(this IFieldExposer<T> obj, string text, bool ignoreCase)
{
MethodInfo containsMethod = typeof(string).GetMethod("Contains", new Type[] { typeof(string) });
var exposedFields = obj.GetFields();
if (ignoreCase)
{
// How should I do convert these to lower too?
// exposedFields = exposedFields.Select(e => e.???.ToLower());
text = text.ToLower();
}
Expression textExp = Expression.Constant(text);
Expression orExpressions = Expression.Constant(false);
foreach (var field in exposedFields)
{
//How should I call the contains method on the string field?
Expression fieldExpression = Expression.Lambda<Func<string>>(Expression.Call(Expression.Constant(obj), field.Method)); //this doesn't work
Expression contains = Expression.Call(fieldExpression, containsMethod, textExp);
orExpressions = Expression.Or(orExpressions, contains);
}
return orExpressions;
}
}
Please check the comments in the code above. I would like to know how to convert all my string properties to lowercase (if desired) and how to call string.Contains in each one of them. I get this error when I create my fieldExpression:
Method 'System.String <GetFields>b__12_0(DataClass)' declared on type 'DataClass+<>c' cannot be called with instance of type 'DataClass'
I don't have experience working with Expression Trees. I've spent hours reading docs and other answers for similar issues but I still can't understand how to achieve what I want... I have no clue what to do now.
I'm testing this in a console app so here's the main class if you want to build it yourself:
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
var data = new DataClass
{
PropertyOne = "Lorem",
PropertyTwo = "Ipsum",
Child = new ChildClass
{
PropertyThree = "Dolor"
}
};
var dataList = new List<DataClass> { data };
var results = dataList.Where(d => d.Match("dolor", true));
}
}
EDIT
I forgot to mention that my dataList should be IQueryable and I want to execute my code in SQL, that's why I'm trying to build the expression trees myself. So it appears my example code should be:
var dataList = new List<DataClass> { data };
var query = dataList.AsQueryable();
var results = query.Where(ExtensionClass.Match<DataClass>("lorem dolor"));
while my method becomes: (I'm following #sjb-sjb's answer and changed the GetFields() method in IFieldExposer<T> to a SelectedFields property)
public static Expression<Func<T, bool>> Match<T>(string text, bool ignoreCase) where T : IFieldExposer<T>
{
ParameterExpression parameter = Expression.Parameter(typeof(T), "obj");
MemberExpression selectedFieldsExp = Expression.Property(parameter, "SelectedFields");
LambdaExpression lambda = Expression.Lambda(selectedFieldsExp, parameter).Compile();
[...]
}
And then it seems that I have to dinamically call selectedFieldsExp with Expression.Lambda. I came up with:
Expression.Lambda(selectedFieldsExp, parameter).Compile();
and that works, but I don't know how to properly call DynamicInvoke() for the lambda expression.
It throws Parameter count mismatch. if I call it without parameters and Object of type 'System.Linq.Expressions.TypedParameterExpression' cannot be converted to type 'DataClass'. if I do DynamicInvoke(parameter).
Any ideas?
Before getting to the implementation, there are some design flaws that needs to be fixed.
First, almost all query providers (except LINQ to Object which simply compiles the lambda expressions to delegates and executes them) don't support invocation expressions and custom (unknown) methods. That's because they do not execute the expressions, but translate them to something else (SQL for instance), and translation is based on pre knowledge.
One example of invocation expression are Func<...> delegates. So the first thing you should do is to use Expression<Func<...>> wherever you currently have Func<...>.
Second, the query expression trees are built statically, i.e. there is no real object instance you can use to obtain the metadata, so the idea of IFieldExposer<T> won't work. You'd need a statically exposed list of expressions like this:
class DataClass //: IFieldExposer<DataClass>
{
// ...
public static IEnumerable<Expression<Func<DataClass, string>>> GetFields()
{
return new List<Expression<Func<DataClass, string>>>
{
a => a.PropertyOne,
b => b.Child.PropertyThree
};
}
}
Then the signature of the method in question could be like this
public static Expression<Func<T, bool>> Match<T>(
this IEnumerable<Expression<Func<T, string>>> fields, string text, bool ignoreCase)
with usage like this
var dataList = new List<DataClass> { data };
var query = dataList.AsQueryable()
.Where(DataClass.GetFields().Match("lorem", true));
Now the implementation. The desired expression could be built purely with Expression class methods, but I'll show you an easier (IMHO) method, which composes expression from compile time expression by replacing the parameter(s) with other expression(s).
All you need is a small helper utility method for replacing lambda expression parameter with another expression:
public static partial class ExpressionUtils
{
public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
{
return new ParameterReplacer { Source = source, Target = target }.Visit(expression);
}
class ParameterReplacer : ExpressionVisitor
{
public ParameterExpression Source;
public Expression Target;
protected override Expression VisitParameter(ParameterExpression node)
=> node == Source ? Target : base.VisitParameter(node);
}
}
Internally it uses ExpressionVistor to find each instance of the passed ParameterExpression and replace it with the passed Expression.
With this helper method, the implementation could be like this:
public static partial class ExpressionUtils
{
public static Expression<Func<T, bool>> Match<T>(this IEnumerable<Expression<Func<T, string>>> fields, string text, bool ignoreCase)
{
Expression<Func<string, bool>> match;
if (ignoreCase)
{
text = text.ToLower();
match = input => input.ToLower().Contains(text);
}
else
{
match = input => input.Contains(text);
}
// T source =>
var parameter = Expression.Parameter(typeof(T), "source");
Expression anyMatch = null;
foreach (var field in fields)
{
// a.PropertyOne --> source.PropertyOne
// b.Child.PropertyThree --> source.Child.PropertyThree
var fieldAccess = field.Body.ReplaceParameter(field.Parameters[0], parameter);
// input --> source.PropertyOne
// input --> source.Child.PropertyThree
var fieldMatch = match.Body.ReplaceParameter(match.Parameters[0], fieldAccess);
// matchA || matchB
anyMatch = anyMatch == null ? fieldMatch : Expression.OrElse(anyMatch, fieldMatch);
}
if (anyMatch == null) anyMatch = Expression.Constant(false);
return Expression.Lambda<Func<T, bool>>(anyMatch, parameter);
}
}
The input => input.ToLower().Contains(text) or input => input.Contains(text) is our compile time match expression, which we then replace the input parameter with the body of the passed Expression<Func<T, string>> lambda expressions, with their parameter replaced with a common parameter used in the final expression. The resulting bool expressions are combined with Expression.OrElse which is the equivalent of the C# || operator (while Expression.Or is for bitwise | operator and in general should not be used with logical operations). Same btw for && - use Expression.AndAlso and not Expression.And which is for bitwise &.
This process is pretty much the expression equivalent of the string.Replace. In case the explanations and code comments are not enough, you can step through the code and see the exact expression transformations and expression building process.
There is no need to get into the complexities of dynamically creating an Expression, because you can just invoke the Func delegate directly:
public interface IFieldExposer<T>
{
IEnumerable<Func<T,string>> SelectedFields { get; }
}
public static class FieldExposerExtensions
{
public static IEnumerable<Func<T,string>> MatchIgnoreCase<T>( this IEnumerable<Func<T,string>> stringProperties, T source, string matchText)
{
return stringProperties.Where(stringProperty => String.Equals( stringProperty( source), matchText, StringComparison.OrdinalIgnoreCase));
}
}
class DataClass : IFieldExposer<DataClass>
{
public string PropertyOne { get; set; }
public string PropertyTwo { get; set; }
public ChildClass Child { get; set; }
public IEnumerable<Func<DataClass, string>> SelectedFields {
get {
return new Func<DataClass, string>[] { #this => #this.PropertyOne, #this => #this.Child.PropertyThree };
}
}
public override string ToString() => this.PropertyOne + " " + this.PropertyTwo + " " + this.Child.PropertyThree;
}
class ChildClass
{
public string PropertyThree { get; set; }
}
Then to use it,
class Program
{
static void Main(string[] args)
{
var data = new DataClass {
PropertyOne = "Lorem",
PropertyTwo = "Ipsum",
Child = new ChildClass {
PropertyThree = "Dolor"
}
};
var data2 = new DataClass {
PropertyOne = "lorem",
PropertyTwo = "ipsum",
Child = new ChildClass {
PropertyThree = "doloreusement"
}
};
var dataList = new List<DataClass>() { data, data2 };
IEnumerable<DataClass> results = dataList.Where( d => d.SelectedFields.MatchIgnoreCase( d, "lorem").Any());
foreach (DataClass source in results) {
Console.WriteLine(source.ToString());
}
Console.ReadKey();
}
}
Following up on my comment above, I think you could do it like this:
class DataClass
{
…
static public Expression<Func<DataClass,bool>> MatchSelectedFields( string text, bool ignoreCase)
{
return #this => (
String.Equals( text, #this.PropertyOne, (ignoreCase? StringComparison.OrdinalIgnoreCase: StringComparison.Ordinal))
|| String.Equals( text, #this.Child.PropertyThree, (ignoreCase? StringComparison.OrdinalIgnoreCase: StringComparison.Ordinal))
);
}
}
Then the query is just
Expression<Func<DataClass,bool>> match = DataClass.MatchSelectedFields( "lorem", ignoreCase);
IEnumerable<DataClass> results = dataList.Where( d => match(d));
I wouldn't usually post a second answer but I thought it would be useful to see how to avoid dynamic modification of Expressions.
Caveat: I didn't actually try to compile it.

How do I construct an Action<T> from lambda expression?

I have this code:
public static Tween.TweenExecuter To<T>(ref this T thisArg, T to, float time, EasingType easing = EasingType.Linear,
TweenType type = TweenType.Simple, Func<bool> trigger = null, Action callback = null) where T : struct
{
Tween.TweenElement<T> tween = new Tween.TweenElement<T>()
{
from = thisArg,
Setter = x => thisArg = x,
to = to,
time = time,
easing = easing,
type = type,
Trigger = trigger,
Callback = callback
};
tween = t;
return new Tween.TweenExecuter(tween);
}
Setter should be assigned to an Action<T> but compiler complains: error CS1628: Cannot use ref or out parameter 'thisArg' inside an anonymous method, lambda expression, or query expression
How can I use an Action<T> otherwise?
Edit:
Here is the type declaration:
public abstract class BaseTween
{
public float time;
public float currentTime;
public EasingType easing;
public TweenType type;
public bool deleteAtEnd = false;
public Func<bool> Trigger;
public Action Callback;
}
public class TweenElement<T> :BaseTween
{
public Action<T> Setter;
public T from;
public T to;
}
You can eliminate the ref keyword and replace it with a different form of indirection, e.g. a container class. In this example I create a container class named Ref which is designed solely to hold another value.
class Ref<T>
{
public T Value { get; set; }
public Ref(T item)
{
Value = item;
}
public override string ToString()
{
return Value.ToString();
}
public static implicit operator T(Ref<T> source)
{
return source.Value;
}
}
I can still no longer pass anything by reference, but if I pass a Ref object, the method can update its properties.
public class Program
{
static Ref<Foo> _container = new Ref<Foo>(null);
static void MyMethod(Ref<Foo> thisArg)
{
Action action = () => thisArg.Value = new Foo("After");
action();
}
public static void Main()
{
_container.Value = new Foo("Before");
Console.WriteLine("Value before call is: {0}", _container);
MyMethod(_container);
Console.WriteLine("Value after call is: {0}", _container);
}
}
Output:
Value before call is: Before
Value after call is: After
See a working example on DotNetFiddle.
Edit: To put the solution into your code, here is what yours might look like:
public static Tween.TweenExecuter To<T>(this Ref<T> thisArg, T to, float time, EasingType easing = EasingType.Linear, TweenType type = TweenType.Simple, Func<bool> trigger = null, Action callback = null) where T : struct
{
Tween.TweenElement<T> tween = new Tween.TweenElement<T>()
{
from = thisArg,
Setter = x => thisArg.Value = x,
to = to,
time = time,
easing = easing,
type = type,
Trigger = trigger,
Callback = callback
};
return new Tween.TweenExecuter(tween);
}

Ambiguous constructor call error

I have a class called Test which has a constructor to accept Action<T> and the other one accepts Func<T,T>. Please see the below snippet.
public class Test<T>
{
//constructors
public Test() { }
public Test(Action<T> action) { }
public Test(Func<T, T> action) { }
//methods with same signature of constructor
public void MyMethod1(Action<T> action) { }
public void MyMethod2(Func<T, T> action) { }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Test<string> t1 = new Test<string>(this.MyMethod1);
Test<string> t2 = new Test<string>(this.MyMethod2);
Test<string> t = new Test<string>();
t.MyMethod1(MyMethod1);
t.MyMethod2(MyMethod2);
}
public void MyMethod1(string value) { }
public string MyMethod2(string value) { return string.Empty; }
}
But below lines throws an ambiguous call error
Test<string> t1 = new Test<string>(this.MyMethod1);
Test<string> t2 = new Test<string>(this.MyMethod2);
and the interesting point is, I have two methods with the same signature of my Test class constructor which not throwing any ambiguous error
Test<string> t = new Test<string>();
t.MyMethod1(MyMethod1);
t.MyMethod2(MyMethod2);
Could anyone please help me to identify and fix the issue.
The return value of a method is not part of its signature. Only the parameters are considered. Hence, the compiler cannot distinguish between Action<T> and Func<T,T>. A detailed explanation and workarounds can be found in this StackOverflow question
You can try renaming the parameters for each of your constructors like so:
public class Test<T>
{
public Test() { }
public Test(Action<T> action) { }
public Test(Func<T,T> function) { }
}
So when you instantiate your class you can specify the name of the parameter like so:
var objectWithAction = new Test<string>(action: Method1);
var objectWithFunction = new Test<string>(function: Method2);
Fact
method / constructor overloading can recognize the correct method by the parameter types but does not include the return type.
Reason
And since in both of the mentioned constructor calls in the question the parameter is of type MethodGroup so the compiler is unable to determine the correct overload. secondly calls to the method are successful as that in not an overloading scenario.
Resolution
here are the possible options to solve the issue
wrapping the method call into an anonymous method call and let the implicit conversion to distinguish themselves.
Test<string> t1 = new Test<string>(s => this.MyMethod1(s));
Test<string> t2 = new Test<string>(s => { return this.MyMethod2(s); });
result
Alternate approach
other option is to explicitly cast the method group
Test<string> t1 = new Test<string>((Action<string>)this.MyMethod1);
Test<string> t2 = new Test<string>((Func<string, string>)this.MyMethod2);
this is bit longer then the first approach if parameters are less
here a working console application sample
class Program
{
static void Main(string[] args)
{
Test<string> t1 = new Test<string>(action: MyMethod1);
Test<string> t2 = new Test<string>(function: MyMethod2);
Test<string> t = new Test<string>();
t.MyMethod1(MyMethod1);
t.MyMethod2(MyMethod2);
}
public static void MyMethod1(string value)
{
Console.WriteLine("my method1 {0}", value);
}
public static string MyMethod2(string value)
{
Console.WriteLine("my method2 {0}", value);
return string.Empty;
}
}
public class Test<T>
{
//constructors
public Test() { }
public Test(Action<T> action)
{
object args = "action";
action.Invoke((T)args); // here you should invoke the method in order to execute it
}
public Test(Func<T, T> function)
{
object args = "function";
function.Invoke((T)args);
}
//methods with same signature of constructor
public void MyMethod1(Action<T> action)
{
object args = "Method 3";
action.Invoke((T)args);
}
public void MyMethod2(Func<T, T> action)
{
object args = "Method 4";
action.Invoke((T)args);
}
}
hope it will help you
regards

Get reference to parameter inside a Lambda passed as a Func

Given the following set of classes:
public class MyClass
{
public int MyInt { get; set; }
}
public class ObjectProcessor
{
public int ProcessObject(MyClass myClass)
{
return myClass.MyInt ++;
}
}
public class Runner
{
public void Run()
{
var classToPass = new MyClass();
FuncExecutor.ExecuteAction<MyClass>(x => x.ProcessObject(classToPass));
}
}
public static class FuncExecutor
{
public static void ExecuteAction<T>(Expression<Func<ObjectProcessor, int>> expression)
{
// var func = expression.Compile(); ... does having an Expression help?
// How can I get a reference to 'classToPass' at this point?
// The 'classToPass' Type is known to be 'T', in this case 'MyClass'.
}
}
From within the ExecuteAction method, how can I get a reference to the classToPass instance that was passed in to ProcessObject?
EDIT: The comments have highlighted the complexity of trying to parse Expression Trees which could vary widely in their composition.
However, in this particular case there are two facts which cut down this variation considerably:
ProcessObject will only ever take a single parameter.
The parameter type is known in advance.
Code altered to express this.
To answer very specifically:
public class Runner
{
public void Run()
{
var classToPass = new MyClass();
classToPass.MyInt = 42;
FuncExecutor.ExecuteAction(x => x.ProcessObject(classToPass));
}
}
public class FuncExecutor
{
public static void ExecuteAction(Expression<Func<ObjectProcessor, int>> expression)
{
var lambdaExpression = (LambdaExpression)expression;
var methodCallExpression = (MethodCallExpression)lambdaExpression.Body;
var memberExpression = (MemberExpression)methodCallExpression.Arguments[0];
var constantExpression = (ConstantExpression)memberExpression.Expression;
var fieldInfo = (FieldInfo)memberExpression.Member;
var myClassReference = (MyClass) fieldInfo.GetValue(constantExpression.Value);
Console.WriteLine(myClassReference.MyInt); // prints "42"
}
}
Please note that when you pass the lambda to the ExecuteAction method, you capture a local variable reference (classToPass). The compiler will generate some code to handle that properly. More precisely, it will generate a type with a single member (a field) of type MyClass to hold the reference and use it from this point. That's why you'll get a MemberExpression in the argument expression list.
Since you can't directly manipulate this generated type, you can't just use the member expression Value property. But you can dynamically invoke the member accessor using the MemberInfo and the target reference (an instance of the compiler generated type).
I would not rely on this code.
You can read more about lambda related compiler generated code here, for example: http://thewalkingdev.blogspot.fr/2012/04/c-lambda-expressions-and-closures.html
The easiest way is to pass the instance as parameter and let ExecuteAction take care of calling the process method using that instance. To do this it is necessary to give your code a little bit of structure using a generic object processor interface:
public interface IObjectProcessor<T> {
public int ProcessObject(T instance);
}
public class MyClassProcessor : IObjectProcessor<MyClass> {
public int ProcessObject(MyClass myClass) {
return myClass.MyInt ++;
}
}
public class Runner {
public void Run() {
var classToPass = new MyClass();
var processor = new MyClassProcessor();
FuncExecutor.ExecuteAction<MyClass>(processor, classToPass);
}
}
public class FuncExecutor {
public static void ExecuteAction<T>(IObjectProcessor<T> processor, T obj) {
int result = processor.ProcessObject(obj);
}
}
This design could be a little annoying especially if your processor are "stateless" and if you really need a Func as parameter. In this case you can drop the interface and use static processors:
public class MyClassProcessor
public static int ProcessObject(MyClass myClass) {
return myClass.MyInt ++;
}
}
public class Runner {
public void Run() {
var classToPass = new MyClass();
FuncExecutor.ExecuteAction<MyClass>(MyClassProcessor.ProcessObject, classToPass);
}
}
public class FuncExecutor {
public static void ExecuteAction<T>(Func<T, int> process, T obj) {
int result = process(obj);
}
}

Extension method selection using generic types and Expressions

I have some extension methods that use an Expression parameter to pull in a property member and act on it, and I have an overload for the specific case where the member is an IEnumerable<>. However, it doesn't seem to match the expected method overload when called from inside a generic class (for r4 below). Outside of the class the correct method is selected.
What's going on here? Will this ever work or do I need to find a new approach?
(This is in C# 5)
public class Test
{
public void MyTest()
{
// returns "Object"
var r1 = new MyClass<object>().Ext(a => a.Content);
// returns "Enumerable"
var r2 = new MyClass<IEnumerable<object>>().Ext(a => a.Content);
// returns "Object"
var r3 = new MyClass<object>().TestExt();
// returns "Object" (I was expecting "Enumerable")
var r4 = new MyClass<IEnumerable<object>>().TestExt();
// returns "Enumerable"
var r5 = new MyClass<int>().TestExt2();
}
}
public class MyClass<T>
{
public T Content { get; set; }
public IEnumerable<object> OtherContent { get; set; }
public string TestExt()
{
return this.Ext(a => a.Content);
}
public string TestExt2()
{
return this.Ext(a => a.OtherContent);
}
}
public static class MyExtensions
{
public static string Ext<T>(this T obj, Expression<Func<T, IEnumerable<object>>> memberExpression)
{
return "Enumerable";
}
public static string Ext<T>(this T obj, Expression<Func<T, object>> memberExpression)
{
return "Object";
}
}
Generics are not dynamic typing. Which overload to call is frozen at compile-time. When the program is later run, even if the variable happens to hold a more specific run-time type, that doesn't matter because the overload was fixed at compile-time.
Your method:
public string TestExt()
{
return this.Ext(a => a.Content);
}
has to bind at compile-time to one specific overload of Ext. Since all we know about T (the type of a.Content) in the class MyClass<T> is that it is convertible to object, there is really only one overload to choose from, so this is easy for the compiler.
From then on, the TestExt method body is hard-coded to calling that specific overload of Ext.
EDIT: Here's a much simpler example:
static void Main()
{
IEnumerable<object> e = new List<object>();
var r = Generic(e);
}
static string Generic<T>(T x)
{
return Overloaded(x);
}
static string Overloaded(IEnumerable<object> x)
{
return "Enumerable";
}
static string Overloaded(object x)
{
return "Object";
}
and as you understand by now, r becomes "Object".
(If you constrained T somehow, for example where T : IEnumerable<object>, things would be different).
Also this is the same for operators. For example the == operator is overloaded in the sense that it works in one way for general reference types, and in another for strings. So in the example below, operator == takes the role of Overloaded from before:
static void Main()
{
string str1 = "abc";
string str2 = "a";
str2 += "bc"; // makes sure this is a new instance of "abc"
bool b1 = str1 == str2; // true
bool b2 = Generic(str1, str2); // false
}
static bool Generic<T>(T x, T y) where T : class
{
return x == y;
}
where b2 becomes false.

Categories

Resources