9

好的,所以我想创建一个通用类来更改数据类型的值。我想这样做的原因是我可以有撤消和重做方法。我可以为我需要的每个值类型编写一个类。IE double, int ...但如果我可以创建一个通用类来执行此操作会容易得多。

这就是我所拥有的

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;
    }
}

但这给了我错误错误“无法获取地址、获取大小或声明指向托管类型 ('T') 的指针”

有没有更好的方法来做到这一点或解决这个错误的方法?

4

5 回答 5

17

只是为了记录,您可以使用这些方法获得指向泛型类型或任何其他类型的指针......

    /// <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)
    }

我已经使用它们和其他一些方法来实现一种与数组一起使用的切片形式。

于 2016-05-04T00:56:55.590 回答
10

与其提供指向值的指针,不如提供一个 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);
于 2013-06-17T20:28:49.570 回答
10

C# 7.3 用新的通用约束解决了这个问题 - unmanaged.

基本上它允许做这样的事情:

void Hash<T>(T value) where T : unmanaged
{
    // Okay
    fixed (T* p = &value) 
    { 
        ...
    }
}

文档

于 2020-06-07T20:25:30.130 回答
-4

不要使用指针,如另一个答案和评论中所述。如果你想在你的应用程序中有一些撤销/重做功能,你可能想研究一下Memento 模式

于 2013-06-17T20:27:10.000 回答
-5

不要使用指针。

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

于 2013-06-17T20:25:36.490 回答