C# 在C中使用自由泛型类型参数模拟委托#
这是一个关于语言设计、模式和语义的难题。请不要因为看不到实际价值就否决投票。 首先,让我们考虑函数及其参数。然后,我们将研究带有参数/参数的函数与带有类型参数/类型参数的泛型类/函数之间的类比 函数是带有一些未指定值的代码块,称为“参数”。 您提供参数并接收结果 泛型类是具有一些未指定的“类型参数”的类。 您可以提供类型参数,然后使用类-调用构造函数或调用静态方法 非泛型类中的泛型函数是具有一些未指定的“类型参数”和一些未指定的“值参数”的函数。 提供类型参数和值参数以接收结果 委托是指向特定函数的指针。创建委托时,不指定函数参数,而是在以后提供它们 问题是.Net对于具有未指定泛型类型参数的泛型函数没有等效的委托。以后不能为类型参数提供类型值。 我们可以想象委托不仅具有自由值参数,而且还具有自由类型参数。C# 在C中使用自由泛型类型参数模拟委托#,c#,generics,delegates,function-pointers,strong-typing,C#,Generics,Delegates,Function Pointers,Strong Typing,这是一个关于语言设计、模式和语义的难题。请不要因为看不到实际价值就否决投票。 首先,让我们考虑函数及其参数。然后,我们将研究带有参数/参数的函数与带有类型参数/类型参数的泛型类/函数之间的类比 函数是带有一些未指定值的代码块,称为“参数”。 您提供参数并接收结果 泛型类是具有一些未指定的“类型参数”的类。 您可以提供类型参数,然后使用类-调用构造函数或调用静态方法 非泛型类中的泛型函数是具有一些未指定的“类型参数”和一些未指定的“值参数”的函数。 提供类型参数和值参数以接收结果 委托是指向特定函
静态类SomeClass{
//泛型函数
公共静态T GetValue(){
返回默认值(T);
}
}
//创建对泛型函数或方法组的委托
Func{TFree}valueFactory=SomeClass.GetValue;
//创建匿名泛型函数的委托
Func{TFree}listFactory={TFree}(int-capacity)=>新列表(capacity);
下面是我想用C#编写的程序的[伪]代码。我想知道如何在正确的C#程序中实现类似的行为
我们如何用C#中的免费泛型类型参数模拟委托?
我们如何通过非泛型代码传递对具有未知泛型参数的泛型函数的引用/链接?
公共静态类工厂{//这里一切都编译得很好
公共委托ICollection FactoryDelegate(IEnumerable值);
公共静态ICollection CreateList(IEnumerable值){
返回新列表(值);
}
公共静态ICollection CreateSet(IEnumerable值){
返回新的HashSet(值);
}
}
公共类工作者{//非泛型类
Func{TFree}_factory;//TFree是一个“自由”泛型类型参数
公职人员(Func{TFree}工厂){
_工厂=工厂;
}
公共ICollection DoWork(IEnumerable值){//泛型方法
返回_factory{T}(值);//提供T作为类型参数TFree的参数
}
}
公共静态类程序{
公共静态void Main(){
字符串[]值1=新字符串[]{“a”、“b”、“c”};
int[]values2=新的int[]{1,2,2,2};
Worker-listWorker=new-Worker(Factory.CreateList);//传递对泛型函数的引用
Worker setWorker=new Worker(Factory.CreateSet);//传递对泛型函数的引用
ICollection result1=listWorker.DoWork(值1);
ICollection result2=listWorker.DoWork(值2);//.Count==4
ICollection result3=setWorker.DoWork(值2);//计数==2
}
}
查看如何在不指定类型参数的情况下将对泛型函数(Factory.CreateList和Factory.CreateSet)的引用传递给工人类构造函数?稍后使用具体类型化数组调用泛型DoWork函数时,将提供类型参数。DoWork使用类型参数选择正确的函数,将值参数传递给它并返回接收到的值
最终解决方案:在.Net的类型系统中,这实际上没有意义 您所描述的是一个类型构造函数–一个接受一个或多个类型并返回具体(参数化或封闭)类型的“函数” 问题是类型构造函数本身不是类型。不能有开放类型的对象或变量;类型构造函数只能用于生成具体类型 换句话说,在.Net的类型系统中,无法表示对开放函数的引用
你能做的最好的事情就是使用反射;
MethodInfo
可以描述一个开放的泛型方法。您可以通过编写一个泛型方法来获取对open
MethodInfo
的编译时类型安全引用,该泛型方法采用带有伪泛型参数的表达式树:
public MethodInfo GetMethod<TPlaceholder>(Expression<Action> method) {
//Find the MethodInfo and remove all TPlaceholder parameters
}
GetMethod<string>(() => SomeMethod<string>(...));
公共方法信息获取方法(表达式方法){
//查找MethodInfo并删除所有TPlaceholder参数
}
GetMethod(()=>SomeMethod(…);
如果要引用对该参数有约束的开放泛型方法,则必须使用
TPlaceholder
参数;您可以选择满足约束的占位符类型。我认为在该语言中模拟这种情况的方法是不使用委托,而是使用接口。非泛型接口可以包含泛型方法,因此可以使用开放类型参数获取委托的大部分行为
下面是您的示例,它被重新编译为有效的C#程序(请注意,它仍然需要您定义的Factory类):
公共接口IWorker
{
i收集工作(i可数值);
}
公共类ListCreationWorker:IWorker
{
公共ICollection DoWork(IEnumerable值)
{
返回Factory.CreateList(值);
}
}
公共类SetCreationWorker:IWorker
{
公共ICollection DoWork(IEnumerable值)
{
返回Factory.CreateSet(值);
}
}
公共静态类程序{
公共静态void Main(字符串[]args){
字符串[]值1=new st
public static class Factory { //Everything compiles fine here
public delegate ICollection<T> FactoryDelegate<T>(IEnumerable<T> values);
public static ICollection<T> CreateList<T>(IEnumerable<T> values) {
return new List<T>(values);
}
public static ICollection<T> CreateSet<T>(IEnumerable<T> values) {
return new HashSet<T>(values);
}
}
public class Worker { //non-generic class
Func{TFree}<FactoryDelegate<TFree>> _factory; //TFree is a "free" generic type paramenter
public Worker(Func{TFree}<FactoryDelegate<TFree>> factory) {
_factory = factory;
}
public ICollection<T> DoWork<T>(IEnumerable<T> values) { //generic method
return _factory{T}(values); //supplying T as the argument for type parameter TFree
}
}
public static class Program {
public static void Main() {
string[] values1 = new string[] { "a", "b", "c" };
int[] values2 = new int[] { 1, 2, 2, 2 };
Worker listWorker = new Worker(Factory.CreateList); //passing reference to generic function
Worker setWorker = new Worker(Factory.CreateSet); //passing reference to generic function
ICollection<string> result1 = listWorker.DoWork(values1);
ICollection<int> result2 = listWorker.DoWork(values2); //.Count == 4
ICollection<int> result3 = setWorker.DoWork(values2); //.Count == 2
}
}
public MethodInfo GetMethod<TPlaceholder>(Expression<Action> method) {
//Find the MethodInfo and remove all TPlaceholder parameters
}
GetMethod<string>(() => SomeMethod<string>(...));
public interface IWorker
{
ICollection<T> DoWork<T>(IEnumerable<T> values);
}
public class ListCreationWorker : IWorker
{
public ICollection<T> DoWork<T>(IEnumerable<T> values)
{
return Factory.CreateList<T>(values);
}
}
public class SetCreationWorker : IWorker
{
public ICollection<T> DoWork<T>(IEnumerable<T> values)
{
return Factory.CreateSet<T>(values);
}
}
public static class Program {
public static void Main(string[] args) {
string[] values1 = new string[] { "a", "b", "c" };
int[] values2 = new int[] { 1, 2, 2, 2 };
IWorker listWorker = new ListCreationWorker();
IWorker setWorker = new SetCreationWorker();
ICollection<string> result1 = listWorker.DoWork(values1);
ICollection<int> result2 = listWorker.DoWork(values2); //.Count == 4
ICollection<int> result3 = setWorker.DoWork(values2); //.Count == 2
}
}
public static class Factory
{
public static ICollection<T> CreateSet<T>(IEnumerable<T> values)
{
return new HashSet<T>(values);
}
public static ICollection<T> CreateList<T>(IEnumerable<T> values)
{
return new List<T>(values);
}
}
public interface IFactory {
ICollection<T> Create<T>(IEnumerable<T> values);
}
public class Worker { //not generic
IFactory _factory;
public Worker(IFactory factory) {
_factory = factory;
}
public ICollection<T> DoWork<T>(IEnumerable<T> values) { //generic method
return _factory.Create<T>(values);
}
}
public static class Program {
class ListFactory : IFactory {
public ICollection<T> Create<T>(IEnumerable<T> values) {
return Factory.CreateList(values);
}
}
class SetFactory : IFactory {
public ICollection<T> Create<T>(IEnumerable<T> values) {
return Factory.CreateSet(values);
}
}
public static void Main() {
string[] values1 = new string[] { "a", "b", "c" };
int[] values2 = new int[] { 1, 2, 2, 2 };
Worker listWorker = new Worker(new ListFactory());
Worker setWorker = new Worker(new SetFactory());
ICollection<string> result1 = listWorker.DoWork(values1);
ICollection<int> result2 = listWorker.DoWork(values2); //.Count == 4
ICollection<int> result3 = setWorker.DoWork(values2); //.Count == 2
}
}