C#Casting T,其中T:使用Unsafe类将其构造为没有装箱的接口

问题描述 投票:0回答:1

我需要编写一个无分配代码,当从带有结构约束的泛型参数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;
            }

产生的“ setter”委托将允许将属性值设置为实现ID属性的任何结构,而无需进行任何装箱。

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

是否有指针(无双关语?)>

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

我需要编写一个无分配代码,当从带有结构约束的泛型参数T强制转换为访问一个实现的属性的接口时,要避免装箱。我以前解决了这个问题...

c# unsafe
1个回答
0
投票

如果没有装箱,则无法将结构转换为接口。接口调用通过对象标题中的vtable进行工作,而未装箱的结构则没有。

但是,我相信您可以通过使用Delegate.CreateDelegate为受约束的泛型方法创建不受约束的委托来完成您的工作。

// No constraints 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 : IEntityComponent
    {
        target.ID = egid;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.