Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#将T,其中T:struct转换为接口,而无需装箱_C#_Unsafe - Fatal编程技术网

C#将T,其中T:struct转换为接口,而无需装箱

C#将T,其中T:struct转换为接口,而无需装箱,c#,unsafe,C#,Unsafe,我需要编写一个无分配代码,以避免在从带有结构约束的泛型参数T转换到接口以访问一个实现的属性时装箱 我以前使用动态生成的代码和lambda表达式树解决了这个问题,如: public delegate void SetEGIDWithoutBoxingActionCast<T>(ref T target, EGID egid) where T : struct, IEntityComponent; static SetEGIDWithoutBoxingA

我需要编写一个无分配代码,以避免在从带有结构约束的泛型参数T转换到接口以访问一个实现的属性时装箱

我以前使用动态生成的代码和lambda表达式树解决了这个问题,如:

        public delegate void SetEGIDWithoutBoxingActionCast<T>(ref T target, EGID egid) where T : struct, IEntityComponent;

        static SetEGIDWithoutBoxingActionCast<T> MakeSetter()
        {
            if (ComponentBuilder<T>.HAS_EGID)
            {
                Type         myTypeA     = typeof(T);
                PropertyInfo myFieldInfo = myTypeA.GetProperty("ID");

                ParameterExpression targetExp = Expression.Parameter(typeof(T).MakeByRefType(), "target");
                ParameterExpression valueExp  = Expression.Parameter(typeof(EGID), "value");
                MemberExpression    fieldExp  = Expression.Property(targetExp, myFieldInfo);
                BinaryExpression    assignExp = Expression.Assign(fieldExp, valueExp);

                var setter = Expression.Lambda<SetEGIDWithoutBoxingActionCast<T>>(assignExp, targetExp, valueExp).Compile();

                return setter;
            }
public delegate void setegidwhithoutboxingActionCast(ref T target,EGID EGID),其中T:struct,IEntityComponent;
静态SetEGIDWithoutBoxingActionCast MakeSetter()设置
{
如果(ComponentBuilder.HAS\u EGID)
{
类型myTypeA=类型(T);
PropertyInfo myFieldInfo=myTypeA.GetProperty(“ID”);
ParameterExpression targetExp=Expression.Parameter(typeof(T).MakeByRefType(),“target”);
ParameterExpression valueExp=表达式参数(typeof(EGID),“value”);
MemberExpression fieldExp=Expression.Property(targetExp,myFieldInfo);
BinaryExpression assignExp=Expression.Assign(fieldExp,valueExp);
var setter=Expression.Lambda(assignExp,targetExp,valueExp).Compile();
回程设定器;
}
生成的“setter”委托将允许将属性值设置为实现ID属性的任何结构,而无需任何装箱

但是现在我需要在不生成动态代码的情况下解决同样的问题。我做了一些快速的实验,但是不安全的类似乎无法使用任何As方法将结构转换为接口,这可能是因为结构不能直接转换为接口,因为它被视为对象,因此不能直接用指针处理

任何指针(没有双关语)

编辑:我不一定需要将结构强制转换到接口,我只需要能够在属性ID中写入值。事实上,它是属性而不是字段,这一点毫无帮助(因为我发现一些代码能够计算结构中字段的偏移量,但当然不能用于属性)

答案被接受,最终代码是这样的,它可以正常工作:

public delegate void SetEGIDWithoutBoxingActionCast<T>(ref T target, EGID egid) where T : struct, IEntityComponent;

static class SetEGIDWithoutBoxing<T> where T : struct, IEntityComponent
{
    public static readonly SetEGIDWithoutBoxingActionCast<T> SetIDWithoutBoxing = MakeSetter();

    public static void Warmup() { }

    static SetEGIDWithoutBoxingActionCast<T> MakeSetter()
    {
        if (ComponentBuilder<T>.HAS_EGID)
        {
            var method = typeof(Trick).GetMethod(nameof(Trick.SetEGIDImpl)).MakeGenericMethod(typeof(T));
            return (SetEGIDWithoutBoxingActionCast<T>) Delegate.CreateDelegate(
                typeof(SetEGIDWithoutBoxingActionCast<T>), method);
        }

        return null;
    }

    static class Trick
    {    
        public static void SetEGIDImpl<U>(ref U target, EGID egid) where U : struct, INeedEGID
        {
            target.ID = egid;
        }
    }
}
public delegate void setegidwhithoutboxingActionCast(ref T target,EGID EGID),其中T:struct,IEntityComponent;
静态类SetEgidWithout-boxing,其中T:struct,IEntityComponent
{
public static readonly SetEGIDWithoutBoxingActionCast SetIDWithoutBoxing=MakeSetter();
公共静态无效预热(){}
静态SetEGIDWithoutBoxingActionCast MakeSetter()设置
{
如果(ComponentBuilder.HAS\u EGID)
{
var method=typeof(Trick).GetMethod(nameof(Trick.SetEGIDImpl)).MakeGenericMethod(typeof(T));
return(SetEGIDWithoutBoxingActionCast)Delegate.CreateDelegate(
类型(设置为不带OutboxingActionCast),方法);
}
返回null;
}
静态类技巧
{    
公共静态void SetEGIDImpl(ref U target,EGID EGID),其中U:struct,inededged
{
target.ID=egid;
}
}
}

如果不装箱,就无法将结构强制转换为接口。接口调用通过对象标头中的vtable工作,而未装箱的结构没有vtable

但是,我相信您可以通过使用
delegate.CreateDelegate
为受约束的泛型方法创建一个无约束的委托来完成所要做的事情

// No constraints needed on the delegate type
public delegate void SetEGIDWithoutBoxingActionCast<T>(ref T target, EGID egid);

public static SetEGIDWithoutBoxingActionCast<T> MakeSetter<T>()
{
    var method = typeof(Foo).GetMethod(nameof(Foo.SetEGIDImpl)).MakeGenericMethod(typeof(T));
    return (SetEGIDWithoutBoxingActionCast<T>)Delegate.CreateDelegate(typeof(SetEGIDWithoutBoxingActionCast<T>), method);
}

public static class Foo
{    
    public static void SetEGIDImpl<T>(ref T target, EGID egid) where T : INeedEGID
    {
        target.ID = egid;
    }
}
//委托类型不需要约束
公共委托无效设置EGIDWithoutboxingActionCast(参考T目标,EGID EGID);
public static SetEGIDWithoutBoxingActionCast MakeSetter()的
{
var method=typeof(Foo).GetMethod(nameof(Foo.SetEGIDImpl)).MakeGenericMethod(typeof(T));
return(SetEGIDWithoutBoxingActionCast)Delegate.CreateDelegate(typeof(SetEGIDWithoutBoxingActionCast),方法);
}
公共静态类Foo
{    
公共静态void SetEGIDImpl(ref T target,EGID EGID),其中T:inededged
{
target.ID=egid;
}
}

你用
不安全的
类做了什么尝试?你能在这里发布一些代码吗?顺便说一句,向接口强制转换结构需要装箱,这是无法避免的。是的,它会起作用,但我不能设置那个约束。事实上,我有一个if来确保在创建委托之前结构正在实现接口(if(ComponentBuilder.HAS_EGID))(但是,如果找不到解决方案,我可以用一个委托字典来解决)。我假设
ID
属性是
IEntityComponent
的一部分,根据您的问题,这是您想要将
T
转换到的接口。不是这样吗?这里唯一的约束是
SetEGIDImpl
,它不是静态调用的。对象必须实现IEntityComponent,也可以是INeedEGID.ID是INEEDGID.if(ComponentBuilder.HAS_EGID)的属性如果INeedEGID是实现的,则返回true。对不起,我指的是结构,而不是对象。你的解决方案似乎是有效的。我从来没有想过用反射来创建一个泛型方法,它可以接受任何约束!在接受之前,我会做更多的测试。如果我接受它,我会感激地给我展示这个简单的技巧: