Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.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# 泛型指针?_C#_Generics_Pointers_Value Type - Fatal编程技术网

C# 泛型指针?

C# 泛型指针?,c#,generics,pointers,value-type,C#,Generics,Pointers,Value Type,好的,我想创建一个泛型类来更改数据类型的值。我想这样做的原因是,我可以有撤销和重做方法。我可以为我需要的每个valuetype编写一个类。也就是说,双倍,整数。。。但是如果我可以创建一个泛型类来完成这项工作,那就容易多了 这就是我所拥有的 class CommandChangeDouble : Command { double _previous; double _new; double* _objectRef; public unsafe CommandCha

好的,我想创建一个泛型类来更改数据类型的值。我想这样做的原因是,我可以有撤销和重做方法。我可以为我需要的每个valuetype编写一个类。也就是说,双倍,整数。。。但是如果我可以创建一个泛型类来完成这项工作,那就容易多了

这就是我所拥有的

class CommandChangeDouble : Command
{
    double _previous;
    double _new;
    double* _objectRef;

    public unsafe CommandChangeDouble(double* o, double to)
    {
        _objectRef = o;
        _previous = *o;
        _new = to;
        *_objectRef = _new;
    }

    public unsafe void Undo()
    {
        *_objectRef = _previous;
    }
    public unsafe void Redo()
    {
        *_objectRef = _new;
    }
}
这就是我想要的

class CommandChangeValue<T> : Command
{
    T _previous;
    T _new;
    T* _objectRef;

    public unsafe CommandChangeValue(T* o, T to)
    {
        _objectRef = o;
        _previous = *o;
        _new = to;
        *_objectRef = _new;
    }

    public unsafe void Undo()
    {
        *_objectRef = _previous;
    }
    public unsafe void Redo()
    {
        *_objectRef = _new;
    }
}
class CommandChangeValue:命令
{
T_先前;
T_new,;
T*_objectRef;
公共不安全命令更改值(T*o,T到)
{
_objectRef=o;
_先前=*o;
_新=到;
*_objectRef=_new;
}
公共不安全的void Undo()
{
*_objectRef=_previous;
}
公共无效重做()
{
*_objectRef=_new;
}
}
但这给了我一个错误“无法获取托管类型('T')的地址、大小或声明指向托管类型('T')的指针”

是否有更好的方法来执行此操作或绕过此错误?

不要使用指针。
如果您使用普通引用,并且始终通过此类中的属性与值交互,则一切都会正常工作。

不要使用指针,如另一个答案和注释中所述。如果你想在你的应用程序中有一些撤销/重做功能,你可能想查看。与其提供一个指向该值的指针,不如提供一个setter:

class CommandChangeValue<T> : Command
{
    T _previous;
    T _new;
    Action<T> _set;

    public CommandChangeValue(T value, Action<T> setValue, T newValue)
    {
        _previous = value;
        _new = newValue;
        _set = setValue;
        setValue(_new);
    }

    public void Undo() { _set(_previous); }
    public void Redo() { _set(_new); }
}


// ...
double v = 42;
var c = new CommandChangeValue(v, d => v = d, 99);
class CommandChangeValue:命令
{
T_先前;
T_new,;
动作集;
公共命令更改值(T值、操作集值、T新值)
{
_先前=值;
_新=新值;
_设置=设置值;
设置值(_新);
}
public void Undo(){_set(_previous);}
public void Redo(){u set(_new);}
}
// ...
双v=42;
var c=新的CommandChangeValue(v,d=>v=d,99);

仅对于记录,您可以使用这些方法获取指向泛型类型或任何其他类型的指针

    /// <summary>
    /// Provides the current address of the given element
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="t"></param>
    /// <returns></returns>
    [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static System.IntPtr AddressOf<T>(T t)
        //refember ReferenceTypes are references to the CLRHeader
        //where TOriginal : struct
    {
        System.TypedReference reference = __makeref(t);

        return *(System.IntPtr*)(&reference);
    }

    [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    static System.IntPtr AddressOfRef<T>(ref T t)
    //refember ReferenceTypes are references to the CLRHeader
    //where TOriginal : struct
    {
        System.TypedReference reference = __makeref(t);

        System.TypedReference* pRef = &reference;

        return (System.IntPtr)pRef; //(&pRef)
    }
//
///提供给定元素的当前地址
/// 
/// 
/// 
/// 
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInline)]
公共静态系统.IntPtr地址(T)
//refember ReferenceTypes是对CLR标头的引用
//where-TOriginal:struct
{
System.TypedReference引用=uu makeref(t);
return*(System.IntPtr*)(&reference);
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInline)]
静态System.IntPtr地址OFREF(参考T)
//refember ReferenceTypes是对CLR标头的引用
//where-TOriginal:struct
{
System.TypedReference引用=uu makeref(t);
System.TypedReference*pRef=&reference;
返回(System.IntPtr)pRef;//(&pRef)
}
我已经使用它们和其他一些工具来实现一种与数组一起使用的切片形式。

C#7.3使用新的通用约束解决了这个问题-
非托管

基本上,它允许这样做:

void散列(T值),其中T:unmanaged
{
//好的
固定(T*p=&值)
{ 
...
}
}

此类问题的答案始终是:不要使用指针。请注意,如果要多次撤消,则需要使用堆栈。NET中的引用是类型安全指针。。。在C#中使用“纯”指针有点过火。@SLaks是的,我不想使用指针,但我想不出其他方法来实现我想要的。还有,我有两个列表来跟踪撤销和重做。问题是,您只能对不包含引用的值类型创建指针,并且不能将泛型参数约束到这些类型。问题是,这些类中有多个与相同的值交互。我也不能使它成为静态的,因为也会有不同的值。你可以使用指针。指针是有效的,有时对高性能应用程序很重要。这是一个愚蠢的回答……你通过提问变得“足够熟练”。再一次。愚蠢的回答:“不,要熟练地有效地使用指针,你必须阅读整本书。”这是不可能的。这么说真是荒谬。什么“整本书”专门介绍指针的使用?人们可以/应该询问如何将其用于高性能C#应用程序。我一直在用它们。如果你不想回答人们关于他们的合理问题,没关系,但不要在这个话题上误导和不必要地吓唬人们。指针的使用超出了SO的范围?什么鬼东西?!对于性能关键型代码,我会在必要时使用指针。也从来没有读过关于它的书。一点也不难,就像其他任何东西一样,当你从C/C++的背景中学习它们时会容易得多,在C/C++的背景中它们被广泛使用,但我永远不会理解“我很了不起,因为我知道指针,那些不知道的人太愚蠢了,无法向他们解释”的心态。我还没有遇到一个天生就有“无所不知的指针”基因的人,而且一开始对他们一无所知。嗯,这看起来像是我正在寻找的,因为我没有使用指针。虽然我将不得不熟悉动作类。你如何做相反的事情并从IntPtr返回到T类型?仔细看,阅读或阅读哇,太棒了。我以前怎么没见过这种情况,嘎……如果我想从枚举类型中获取原始数据,我的生活会变得更轻松。我最终使用了泛型类型缓存编译的强制转换表达式,每个底层枚举类型都需要太多重复代码。这是爱。我不知道哪一个更有效。你应该在你的答案中包含读取函数:)昨晚为此苦苦挣扎。需要一个指向泛型数组第一项的指针,在这里我(但不是编译器)知道数组是固定大小的值类型,并且能够锁定arr占用的内存