【问题标题】:Pointers of generic type?泛型类型的指针?
【发布时间】:2013-06-13 22:02:01
【问题描述】:

好的,所以我想创建一个通用类来更改数据类型的值。我想这样做的原因是我可以有撤消和重做方法。我可以为我需要的每个值类型编写一个类。 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') 的指针”

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

【问题讨论】:

  • 这类问题的答案总是:不要使用指针。
  • 请注意,如果您想多次撤消,则需要一个堆栈。
  • .NET 中的引用是类型安全的指针...在 C# 中使用“纯”指针有点过头了。
  • @SLaks 是的,我不想使用指针,但我想不出另一种方法来实现我想要的。也是的,我有 2 个 List 来跟踪 Undo 和 Redo
  • 问题是你只能做一个不包含引用的值类型的指针,你不能将泛型参数约束到这些类型。

标签: c# generics pointers value-type


【解决方案1】:

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

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

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

【讨论】:

  • 你如何做相反的事情并从 IntPtr 返回键入 T?
  • 哇,太棒了。我以前怎么没见过这个,gah...如果尝试从枚举类型中获取原始位,我的生活会更轻松。我最终使用了通用类型缓存的编译转换表达式,每个底层枚举类型都需要太多重复的代码。这很可爱。我想知道哪个性能更好。
  • 你应该在你的答案中包含阅读功能:)
  • 昨晚为此苦苦挣扎。需要一个指向通用数组的第一项的指针,我(但不是编译器)知道该数组是固定大小的值类型,并且能够固定该数组占用的内存。有些东西告诉我这应该可以完成这项工作。对__makeref 的使用也很感兴趣。以前没见过。
【解决方案2】:

提供一个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);

【讨论】:

  • 嗯,这看起来就像我在寻找不使用指针的额外好处。虽然我将不得不熟悉 Action 类。
【解决方案3】:

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

基本上它允许这样做:

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

Docs

【讨论】:

    【解决方案4】:

    不要使用指针,如另一个答案和 cmets 中所述。如果您想在您的应用程序中添加一些撤消/重做功能,您可能需要查看Memento pattern。

    【讨论】:

      【解决方案5】:

      不要使用指针。

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

      【讨论】:

      • 好吧,问题是这些类中会有多个与相同的值交互。我也不能让它成为静态的,因为也会有不同的值。
      • 您可以使用指针。指针是有效的,有时对于高性能应用程序很重要。这是一个愚蠢的回应。
      • ...您通过提问变得“足够熟练”。再次。愚蠢的回应。
      • "不;要熟练到有效地使用指针,您必须阅读整本书" 没办法。说起来很可笑。哪些“整本书”专门用于指针的使用?人们可以/应该询问如何将它们用于高性能 C# 应用程序。我一直在使用它们。如果你不想回应人们关于他们的合理问题,那很好,但不要在这个话题上不必要地误导和吓唬人们。而指针的使用是超出了SO范围的话题吗?到底是什么人?!
      • 我在必要时对性能关键代码使用指针。也从来没有读过关于它的书。一旦你学会了它们,一点也不难,就像其他任何东西一样,当来自它们最广泛使用的 C/C++ 背景时,会容易得多,但我永远不会理解“我很棒,因为我知道指针,那些不知道指针的人太愚蠢了,无法向他们解释“心态。我还没有遇到过天生就有“全知指针”基因的人,而且一开始对他们一无所知。
      猜你喜欢
      • 2010-10-22
      • 2018-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-18
      相关资源
      最近更新 更多