C# 具有未知类型的CreateDelegate

C# 具有未知类型的CreateDelegate,c#,.net,generics,reflection,delegates,C#,.net,Generics,Reflection,Delegates,我正在尝试创建委托,以便在运行时读取/写入未知类型类的属性 我有一个泛型类Main和一个如下所示的方法: Delegate.CreateDelegate(typeof(Func<T, object>), get) 现在的问题是创建了generic的委托实例,因此我必须使用DynamicInvoke,这与使用纯反射读取字段一样慢 所以我的问题是,为什么第一段代码的值类型失败。根据它的说法,它应该按照它所说的那样工作 如果方法的返回类型比委托的返回类型更严格,则委托的返回类型与方法的返

我正在尝试创建委托,以便在运行时读取/写入未知类型类的属性

我有一个泛型类
Main
和一个如下所示的方法:

Delegate.CreateDelegate(typeof(Func<T, object>), get)
现在的问题是创建了
generic
的委托实例,因此我必须使用
DynamicInvoke
,这与使用纯反射读取字段一样慢

所以我的问题是,为什么第一段代码的值类型失败。根据它的说法,它应该按照它所说的那样工作

如果方法的返回类型比委托的返回类型更严格,则委托的返回类型与方法的返回类型兼容

以及如何在第二个代码段中执行委托,以使其比反射更快


谢谢。

调用失败,因为您需要的对象不是值类型(如INT)——显然
Func
不是
Func
——它不能与任何vt(如double或bool)一起工作。返回一个装箱的Int(或任何你得到的vt)。或者(也许更好)使用反射发射API

通过使用反射发射类,您可以创建动态方法并将其保存为委托,或者创建动态委托并将其保存在某些结构中。您只能这样做一次(可能每个运行时一次)将其存储在某个Dict中,并在需要时调用

希望能有帮助。
luke

您的原始代码只能用于引用类型。这就是为什么字符串不是问题,它直接从System.Object派生。值类型派生自ValueType和Object在纸上是一个很好的错觉,但实际上需要代码。C#编译器自动发出该代码,它需要一个装箱转换。这是这里缺少的部分,如果没有

您可以在代码中获得该操作码,但必须使用System.Reflection.Emit


在你去那里之前,首先检查一下你现在得到的东西是否真的太慢了。反射的代价是从程序集中挖掘元数据。这是在创建委托时完成的,之后会缓存类型信息。

是否可以将泛型方法限制为仅处理引用类型,并创建另一个泛型方法以仅处理值类型,并相应地决定使用哪种功能?

以下是解决问题的一种方法。创建泛型方法:

public static Func<T, object> MakeDelegate<U>(MethodInfo @get)
{
    var f = (Func<T, U>)Delegate.CreateDelegate(typeof(Func<T, U>), @get);
    return t => f(t);
}
public static Func MakeDelegate(MethodInfo@get)
{
var f=(Func)Delegate.CreateDelegate(typeof(Func),@get);
返回t=>f(t);
}

通过这种方式,C#的编译器负责插入必要的装箱(如果有)以将
f(t)
(类型
U
)转换为
对象。现在您可以使用反射调用这个
MakeDelegate
方法,将
U
设置为
@get.ReturnType
,您得到的将是一个
Func
,无需使用
DynamicInvoke
即可调用该方法。我的方法类似于@kvb方法,但使用了包装类。由于使用虚拟方法而不是代理操作,因此它们的工作速度要快一些。此外,代理操作使捕获上下文成为不可见的DisplayClass。这是我的版本

using System;
using System.Reflection;

public abstract class DelegateWrapper
{
    public static DelegateWrapper Create ( object target, MethodInfo method, Type arg ) =>
        Create( target, method, typeof( DelegateWrapper<> ), arg );

    public static DelegateWrapper Create ( object target, MethodInfo method, Type arg1, Type arg2 ) =>
        Create( target, method, typeof( DelegateWrapper<,> ), arg1, arg2 );

    private static DelegateWrapper Create ( object target, MethodInfo method, Type generic, params Type[] argTypes )
    {
        var wrapperType = generic.MakeGenericType( argTypes );
        var ctor = wrapperType.GetConstructor( new Type[] { typeof( object ), typeof( MethodInfo ) } );
        var wrapper = ctor.Invoke( new object[] { target, method } ) as DelegateWrapper;
        return wrapper;
    }

    public virtual void Invoke ( object arg )
    {
        throw new NotSupportedException();
    }
    
    public virtual void Invoke ( object arg1, object arg2 )
    {
        throw new NotSupportedException();
    }
}

public class DelegateWrapper<T> : DelegateWrapper
{
    private Action<T> _delegate;

    public DelegateWrapper ( object target, MethodInfo method )
    {
        _delegate = ( Action<T> )Delegate.CreateDelegate( typeof( Action<T> ), target, method );
    }

    public override void Invoke ( object arg )
    {
        _delegate.Invoke( ( T )arg );
    }
}

public class DelegateWrapper<T1, T2> : DelegateWrapper
{
    private Action<T1, T2> _delegate;

    public DelegateWrapper ( object target, MethodInfo method )
    {
        _delegate = ( Action<T1, T2> )Delegate.CreateDelegate( typeof( Action<T1, T2> ), target, method );
    }

    public override void Invoke ( object arg1, object arg2 )
    {
        _delegate.Invoke( ( T1 )arg1, ( T2 )arg2 );
    }
}

所有的值类型都继承自对象,所以这就是我认为它可以工作的原因。我知道反射发射,但它比CreateDelegates更复杂,但协方差和逆变不适用于值类型。这就是值类型和装箱的全部目的。因为这里没有更多的隐式转换,所以您的意思是在代码段2中生成的委托上使用DynamicInvoke很快,还是我弄错了?目前,我正在使用SetValue/GetValue来写/读属性,并希望加快速度。
using System;
using System.Reflection;

public abstract class DelegateWrapper
{
    public static DelegateWrapper Create ( object target, MethodInfo method, Type arg ) =>
        Create( target, method, typeof( DelegateWrapper<> ), arg );

    public static DelegateWrapper Create ( object target, MethodInfo method, Type arg1, Type arg2 ) =>
        Create( target, method, typeof( DelegateWrapper<,> ), arg1, arg2 );

    private static DelegateWrapper Create ( object target, MethodInfo method, Type generic, params Type[] argTypes )
    {
        var wrapperType = generic.MakeGenericType( argTypes );
        var ctor = wrapperType.GetConstructor( new Type[] { typeof( object ), typeof( MethodInfo ) } );
        var wrapper = ctor.Invoke( new object[] { target, method } ) as DelegateWrapper;
        return wrapper;
    }

    public virtual void Invoke ( object arg )
    {
        throw new NotSupportedException();
    }
    
    public virtual void Invoke ( object arg1, object arg2 )
    {
        throw new NotSupportedException();
    }
}

public class DelegateWrapper<T> : DelegateWrapper
{
    private Action<T> _delegate;

    public DelegateWrapper ( object target, MethodInfo method )
    {
        _delegate = ( Action<T> )Delegate.CreateDelegate( typeof( Action<T> ), target, method );
    }

    public override void Invoke ( object arg )
    {
        _delegate.Invoke( ( T )arg );
    }
}

public class DelegateWrapper<T1, T2> : DelegateWrapper
{
    private Action<T1, T2> _delegate;

    public DelegateWrapper ( object target, MethodInfo method )
    {
        _delegate = ( Action<T1, T2> )Delegate.CreateDelegate( typeof( Action<T1, T2> ), target, method );
    }

    public override void Invoke ( object arg1, object arg2 )
    {
        _delegate.Invoke( ( T1 )arg1, ( T2 )arg2 );
    }
}
object target;
var targetType = target.GetType();
var methodInfo = targetType.GetMethod("MethodWith2Strings");

var delegateWrapper = DelegateWrapper.Create(target, methodInfo, typeof(string), typeof(string));

delegateWrapper.Invoke("String 1", "String 2");