I need to create a delegate for Result property of Task in c#( TResult getter_Result) I am able to get getter method for property Result
Resultgetter = (TaskGenericType).GetProperty("Result").GetGetMethod();
But to add this to delegate , the following are my tries. My tries :
Delegate d = Delegate.CreateDelegate(typeof(MyDelegate), Resultgetter, true);
The signature of Delegate is
public delegate object MyDelegate();
But the issue here is :
I cannot have "object
" as return for my delegate, as the signature has to match with Result property.
When I tried writing TResult
as return for my delegate (
public delegate TResult MyDelegate())
, I am getting error that TResult cannot resolve symbol.
How to create delegate for getter_Result
for Task object.
what I am trying to do : 1.Getting getter method of Result for a Task object . And invoking that getter after one event is done.
So in that process . 1I am able to get getter for Result. But facing issue when I need to assign to delegate because of parameter mismatch. hence , I need to understand how to give return type for Result.
sample code
The problematic code line is
Delegate d = Delegate.CreateDelegate(typeof(MyDelegate), Resultgetter, true); it is going to catch there ,
the stack trace in catch is
System.ArgumentException: Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
at System.Delegate.CreateDelegate(Type type, MethodInfo method, Boolean throwOnBindFailure)
at getProperties.Program.Main(String[] args) in Program.cs:line 126
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
public delegate Task<string> MyDelegate();
class Program
{
static void Main(string[] args)
{
Task<int> task1 = Task<int>.Factory.StartNew(() => 1);
int i = task1.Result;
PropertyInfo[] vals = GetPublicProperties(task1.GetType());
Type TaskGenericType = Type.GetType("System.Threading.Tasks.Task`1");
MethodInfo Resultgetter;
foreach (var x in vals)
{
if (x.ToString().Contains("Result"))
{
try
{
Resultgetter = (TaskGenericType).GetProperty("Result").GetGetMethod();
***Delegate d = Delegate.CreateDelegate(typeof(MyDelegate), Resultgetter, true);***
}
catch (Exception e)
{
Console.WriteLine(e);
Console.WriteLine(e.StackTrace);
throw;
}
}
Console.WriteLine(x.ToString());
}
}
static PropertyInfo[] GetPublicProperties(Type type)
{
if (type.IsInterface)
{
var propertyInfos = new List<PropertyInfo>();
var considered = new List<Type>();
var queue = new Queue<Type>();
considered.Add(type);
queue.Enqueue(type);
while (queue.Count > 0)
{
var subType = queue.Dequeue();
foreach (var subInterface in subType.GetInterfaces())
{
if (considered.Contains(subInterface)) continue;
considered.Add(subInterface);
queue.Enqueue(subInterface);
}
var typeProperties = subType.GetProperties(
BindingFlags.FlattenHierarchy
| BindingFlags.Public
| BindingFlags.Instance);
var newPropertyInfos = typeProperties
.Where(x => !propertyInfos.Contains(x));
propertyInfos.InsertRange(0, newPropertyInfos);
}
return propertyInfos.ToArray();
}
return type.GetProperties(BindingFlags.FlattenHierarchy
| BindingFlags.Public | BindingFlags.Instance);
}
}
sample How I am fetching "IsCompleted" property
foreach (var x in vals)
{
if (x.ToString().Contains("IsCompleted"))
{
try
{
Resultgetter = TaskType.GetProperty("IsCompleted").GetGetMethod();
// Delegate d = Delegate.CreateDelegate(typeof(MyDelegate), Resultgetter, true);
Func<bool> testFunc = Delegate.CreateDelegate(typeof(Func<bool>), null, Resultgetter) as Func<bool>;
Console.WriteLine(10);
}
catch (Exception e)
{
Console.WriteLine(e);
Console.WriteLine(e.StackTrace);
throw;
}
}
Console.WriteLine(x.ToString());
}
You can do this via expression trees, but the way your sample code is set up makes it look like you want just a Func<object>
, which means the task has to be already embedded in the expression tree. You can do that:
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Task<int> task = Task.FromResult(1);
var constantExpression = Expression.Constant(task, task.GetType());
var propertyExpression = Expression.Property(constantExpression, "Result");
var conversion = Expression.Convert(propertyExpression, typeof(object));
var lambda = Expression.Lambda<Func<object>>(conversion);
Func<object> compiled = lambda.Compile();
Console.WriteLine(compiled());
}
}
If you want to do that, you might as well just call Result
with reflection, and then build a delegate that returns that:
using System;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
// Compile-time type object to prove I'm not cheating...
object task = Task.FromResult(1);
var result = task.GetType().GetProperty("Result").GetValue(task);
Func<object> d = () => result;
Console.WriteLine(d()); // 1
}
}
Neither of those looks particularly satisfactory to me, but hopefully you'll be able to get something useful out of them...
See more on this question at Stackoverflow