无法将匿名委托分配给签名委托
Can't assign anonymous delegate to signed delegate
我正在寻找一种方法,将列表中的不同委托分配给 MethodInfo
,而无需事先了解 return 类型的相关信息。下面是我正在使用的代码代码。这些评论提供了有关正在发生的事情的更多信息。这是一段很长的代码,但我已经尽可能地减少了它。
主要代码段
private const string methodName = "Execute";
public static void Main()
{
ExampleClass1 e1 = new ExampleClass1();
ExampleClass2 e2 = new ExampleClass2();
ExampleClass3 e3 = new ExampleClass3();
/* Code below Simulates: "e3.GetString = e2.Execute;" */
var method = e2.GetType().GetMethod(methodName);
for (int i = 0; i < e3.DelegateList.Count; i++)
{
// First check the type of e2 return
Type methodType = method.ReturnType;
// Check that its the same return type as delegate
if (methodType != e3.DelegateList[i].ReturnType)
continue;
// Assign delegate to method
var returnType = e3.DelegateList[i].DelegateType;
e3.DelegateList[i].Delegate = Delegate.CreateDelegate(returnType, e2, method);
/* Code below only for debugging */
Console.WriteLine("The delegate in the list: " + e3.DelegateList[i].Delegate);// Returns Type of StringHandler
Console.WriteLine("The delegate in the object: " + e3.GetString);// Returns null
e3.GetString = e3.DelegateList[i].Delegate;// This throws Error Cannot convert Delegate to StringHandler
}
/* Code above Simulates: "e3.GetString = e2.Execute;" */
e2.GetNumber = e1.Execute;
e3.Execute();// Throws Null References Exception on
// Read the key
Console.ReadKey();
}
支持Classes/Code
如果您需要更多关于支持类的信息,请查看下面的代码。此外,这是一个独立的程序,应该可以按原样运行。
public class ExampleClass3
{
public delegate string StringHandler();
public delegate int IntHandler();
public StringHandler GetString { get; set; }
public IntHandler GetInt { get; set; }
public List<DelegateInfo<Type, Type, Delegate>> DelegateList { get; set; }
public ExampleClass3()
{
DelegateList = new List<DelegateInfo<Type, Type, Delegate>>();
DelegateList.Add(new DelegateInfo<Type, Type, Delegate>(typeof(StringHandler), typeof(string), GetString));
DelegateList.Add(new DelegateInfo<Type, Type, Delegate>(typeof(IntHandler), typeof(int), GetInt));
}
public object Execute()
{
Console.WriteLine(GetString());
return null;
}
}
public class ExampleClass2
{
public delegate int NumberHandler();
public NumberHandler GetNumber { get; set; }
public string Execute() => $"Your Number Is {GetNumber()}";
}
public class ExampleClass1
{
public int number = 5;
public int Execute() => number;
}
public class DelegateInfo<T1, T2, T3>
{
public DelegateInfo(T1 delegateType, T2 returnType, T3 @delegate)
{
DelegateType = delegateType;
ReturnType = returnType;
Delegate = @delegate;
}
public T1 DelegateType { get; set; }
public T2 ReturnType { get; set; }
public T3 Delegate { get; set; }
}
缺少演员:
e3.GetString = (ExampleClass3.StringHandler)e3.DelegateList[i].Delegate;
我稍微简化了您的代码以演示我将如何处理这个问题。首先,不要创建特殊的 DelegateInfo class - 尽可能坚持使用标准的 .NET 反射库。他们在这方面做得非常好 - 但确实需要一段时间来学习。
代码如下:
private const string methodName = "Execute";
public static void Main()
{
ExampleClass1 e1 = new ExampleClass1();
ExampleClass2 e2 = new ExampleClass2();
ExampleClass3 e3 = new ExampleClass3();
/* Code below Simulates: "e3.GetString = e2.Execute;" */
var method = e2.GetType().GetMethod(methodName);
Type methodType = method.ReturnType;
// Create a Func<T> that will invoke the target method
var funcType = typeof(Func<>).MakeGenericType(methodType);
var del = Delegate.CreateDelegate(funcType, e2, method);
var properties = e3.GetType().GetProperties();
for (int i = 0; i < properties.Length; i++)
{
if (properties[i].PropertyType.IsAssignableFrom(funcType)) {
properties[i].SetValue(e3, del );
}
}
/* Code above Simulates: "e3.GetString = e2.Execute;" */
e2.GetNumber = e1.Execute;
e3.Execute();
// Read the key
Console.ReadKey();
}
public class ExampleClass3
{
public Func<String> GetString { get; set; }
public Func<int> GetInt { get; set; }
public ExampleClass3()
{ }
public object Execute()
{
Console.WriteLine(GetString());
return null;
}
}
public class ExampleClass2
{
public Func<int> GetNumber { get; set; }
public string Execute() => $"Your Number Is {GetNumber()}";
}
public class ExampleClass1
{
public int number = 5;
public int Execute() => number;
}
首先,请注意我是如何摆脱自定义委托定义以支持 Func 的。这将证明以通用方式更容易使用。注意 ExampleClass3 现在是如何定义的:
public class ExampleClass3
{
public Func<String> GetString { get; set; }
public Func<int> GetInt { get; set; }
public ExampleClass3()
{ }
public object Execute()
{
Console.WriteLine(GetString());
return null;
}
}
我可以利用所有这些函数都是 Func 类型这一事实来开发一个通用的解决方案来为它们赋值。基于目标方法的 return 类型,我可以构造一个适当类型的 Func 委托(并且 link 将它构造到有问题的特定 e2 实例):
var funcType = typeof(Func<>).MakeGenericType(methodType);
var del = Delegate.CreateDelegate(funcType, e2, method);
现在我可以直接将此委托指定为具有匹配委托类型的任何属性的值:
var properties = e3.GetType().GetProperties();
for (int i = 0; i < properties.Length; i++)
{
if (properties[i].PropertyType.IsAssignableFrom(funcType)) {
properties[i].SetValue(e3, del );
}
}
希望对您有所帮助:)
我正在寻找一种方法,将列表中的不同委托分配给 MethodInfo
,而无需事先了解 return 类型的相关信息。下面是我正在使用的代码代码。这些评论提供了有关正在发生的事情的更多信息。这是一段很长的代码,但我已经尽可能地减少了它。
主要代码段
private const string methodName = "Execute";
public static void Main()
{
ExampleClass1 e1 = new ExampleClass1();
ExampleClass2 e2 = new ExampleClass2();
ExampleClass3 e3 = new ExampleClass3();
/* Code below Simulates: "e3.GetString = e2.Execute;" */
var method = e2.GetType().GetMethod(methodName);
for (int i = 0; i < e3.DelegateList.Count; i++)
{
// First check the type of e2 return
Type methodType = method.ReturnType;
// Check that its the same return type as delegate
if (methodType != e3.DelegateList[i].ReturnType)
continue;
// Assign delegate to method
var returnType = e3.DelegateList[i].DelegateType;
e3.DelegateList[i].Delegate = Delegate.CreateDelegate(returnType, e2, method);
/* Code below only for debugging */
Console.WriteLine("The delegate in the list: " + e3.DelegateList[i].Delegate);// Returns Type of StringHandler
Console.WriteLine("The delegate in the object: " + e3.GetString);// Returns null
e3.GetString = e3.DelegateList[i].Delegate;// This throws Error Cannot convert Delegate to StringHandler
}
/* Code above Simulates: "e3.GetString = e2.Execute;" */
e2.GetNumber = e1.Execute;
e3.Execute();// Throws Null References Exception on
// Read the key
Console.ReadKey();
}
支持Classes/Code
如果您需要更多关于支持类的信息,请查看下面的代码。此外,这是一个独立的程序,应该可以按原样运行。
public class ExampleClass3
{
public delegate string StringHandler();
public delegate int IntHandler();
public StringHandler GetString { get; set; }
public IntHandler GetInt { get; set; }
public List<DelegateInfo<Type, Type, Delegate>> DelegateList { get; set; }
public ExampleClass3()
{
DelegateList = new List<DelegateInfo<Type, Type, Delegate>>();
DelegateList.Add(new DelegateInfo<Type, Type, Delegate>(typeof(StringHandler), typeof(string), GetString));
DelegateList.Add(new DelegateInfo<Type, Type, Delegate>(typeof(IntHandler), typeof(int), GetInt));
}
public object Execute()
{
Console.WriteLine(GetString());
return null;
}
}
public class ExampleClass2
{
public delegate int NumberHandler();
public NumberHandler GetNumber { get; set; }
public string Execute() => $"Your Number Is {GetNumber()}";
}
public class ExampleClass1
{
public int number = 5;
public int Execute() => number;
}
public class DelegateInfo<T1, T2, T3>
{
public DelegateInfo(T1 delegateType, T2 returnType, T3 @delegate)
{
DelegateType = delegateType;
ReturnType = returnType;
Delegate = @delegate;
}
public T1 DelegateType { get; set; }
public T2 ReturnType { get; set; }
public T3 Delegate { get; set; }
}
缺少演员:
e3.GetString = (ExampleClass3.StringHandler)e3.DelegateList[i].Delegate;
我稍微简化了您的代码以演示我将如何处理这个问题。首先,不要创建特殊的 DelegateInfo class - 尽可能坚持使用标准的 .NET 反射库。他们在这方面做得非常好 - 但确实需要一段时间来学习。
代码如下:
private const string methodName = "Execute";
public static void Main()
{
ExampleClass1 e1 = new ExampleClass1();
ExampleClass2 e2 = new ExampleClass2();
ExampleClass3 e3 = new ExampleClass3();
/* Code below Simulates: "e3.GetString = e2.Execute;" */
var method = e2.GetType().GetMethod(methodName);
Type methodType = method.ReturnType;
// Create a Func<T> that will invoke the target method
var funcType = typeof(Func<>).MakeGenericType(methodType);
var del = Delegate.CreateDelegate(funcType, e2, method);
var properties = e3.GetType().GetProperties();
for (int i = 0; i < properties.Length; i++)
{
if (properties[i].PropertyType.IsAssignableFrom(funcType)) {
properties[i].SetValue(e3, del );
}
}
/* Code above Simulates: "e3.GetString = e2.Execute;" */
e2.GetNumber = e1.Execute;
e3.Execute();
// Read the key
Console.ReadKey();
}
public class ExampleClass3
{
public Func<String> GetString { get; set; }
public Func<int> GetInt { get; set; }
public ExampleClass3()
{ }
public object Execute()
{
Console.WriteLine(GetString());
return null;
}
}
public class ExampleClass2
{
public Func<int> GetNumber { get; set; }
public string Execute() => $"Your Number Is {GetNumber()}";
}
public class ExampleClass1
{
public int number = 5;
public int Execute() => number;
}
首先,请注意我是如何摆脱自定义委托定义以支持 Func 的。这将证明以通用方式更容易使用。注意 ExampleClass3 现在是如何定义的:
public class ExampleClass3
{
public Func<String> GetString { get; set; }
public Func<int> GetInt { get; set; }
public ExampleClass3()
{ }
public object Execute()
{
Console.WriteLine(GetString());
return null;
}
}
我可以利用所有这些函数都是 Func 类型这一事实来开发一个通用的解决方案来为它们赋值。基于目标方法的 return 类型,我可以构造一个适当类型的 Func 委托(并且 link 将它构造到有问题的特定 e2 实例):
var funcType = typeof(Func<>).MakeGenericType(methodType);
var del = Delegate.CreateDelegate(funcType, e2, method);
现在我可以直接将此委托指定为具有匹配委托类型的任何属性的值:
var properties = e3.GetType().GetProperties();
for (int i = 0; i < properties.Length; i++)
{
if (properties[i].PropertyType.IsAssignableFrom(funcType)) {
properties[i].SetValue(e3, del );
}
}
希望对您有所帮助:)