【问题标题】:Pointers to a typed variable in C#: Interface, Generic, object or Class? (Boxing/Unboxing)指向 C# 中类型变量的指针:接口、泛型、对象还是类? (装箱/拆箱)
【发布时间】:2011-01-06 00:18:41
【问题描述】:

首先,如果这个问题被问了一千次,我深表歉意。我阅读了我的 C# 书籍,在 Google 上搜索过,但似乎找不到我正在寻找的答案,或者我错过了重点。

我对整个装箱/拆箱问题感到非常困惑。假设我有不同类的字段,所有返回类型变量(例如'double'),我希望有一个变量指向这些字段中的任何一个。在普通的旧 C 中,我会执行以下操作:

double * newVar;
newVar = &oldVar;
newVar = &anotherVar;
...

我有一个计时器调用一个函数并传递引用变量的值:

ChartPlotData(*newVar);

之所以找指针,是因为newVar在运行时发生变化,链接到一个Event:

public void checkbox_Clicked(object sender ...)
  if (sender == checkbox1) value = &object1.field1;
  if (sender == checkbox2) value = &object2.field1;

如何在 C# 中做到这一点?

EDIT1:解释了引用的目的。

EDIT2:做了一些不正确的陈述,删除它们并缩短了问题。

【问题讨论】:

  • 这样引用的目的是什么?
  • 这句话是什么意思? “在 C# 中,我似乎可以做一个接口,但会要求所有字段都是属性并且命名相同。当其中一个属性名称不同或不是属性时会分开。”
  • 我可以强制对象实现一个接口,但这意味着我需要创建一个可能没有意义的所有对象共有的属性。例如,“Car”类可能具有“NrWheels”属性,而“Boat”类可能具有“NrPropellers”属性。如果在运行时,我希望调用 Plot(NrRotatingDevices),我可能会创建一个接口“NrRotatingDevices”,但必须修改两个类以实现此接口或将 NrPropellers 和 NrWheels 重命名为 NrRotatingDevices。
  • 改写问题并删除不正确的陈述。

标签: c# variables pointers boxing typed


【解决方案1】:

您可以按照编辑中的建议进行单击事件,然后使用委托选择要传递给控件的数据。不过,我不确定这是否能满足您的性能要求。

ChartPlotData(valueSelector());

// ...

Func<double> valueSelector;

protected void Checkbox_Click(object sender /* ... */)
{
    if (sender == checkbox1) valueSelector = () => object1.field1;
    if (sender == checkbox2) valueSelector = () => object2.field1;
    // ...
}

(如果您愿意并且可以的话,您可以重载ChartPlotData 方法以接受Func&lt;double&gt; 而不是普通的double,然后在方法内部懒惰地调用选择器委托而不是在呼叫站点。)

【讨论】:

    【解决方案2】:

    简单类型和结构在 C# 中属于值类型。除非您提到使用 unsafe 修饰符,否则您无能为力。话虽如此,您的选择是有限的。

    1. 使用对象而不是原始类型。
    2. 使用大小为 1 的数组。
    3. 自定义的通用代理类封装了上述任何一个。
    4. ???

    【讨论】:

    • 如果您要使用通用代理类,您应该只对值进行装箱/拆箱,因为这就是您实际上正在做的事情。
    • @yodaj007:对,代理正在存储值类型。但是现在因为它是一个类,你可以通过引用传递它,例如VTP d = 新 VTP(1.2); VTP d1 = d;请参阅 petro.sidlovskyy 的回复。 d1.Value = 3.1;断言(d.value == 3.1);
    【解决方案3】:

    您可以使用ref keyword 引用现有的值类型。

    public static void ModifyNumber(ref int i)
    {
        i += 1;
    }
    
    static void Main(string[] args)
    {
        int num = 4;
        ModifyNumber(ref num);
        ModifyNumber(ref num);
        ModifyNumber(ref num);
        ModifyNumber(ref num);
    
    
        // num now equals 8
    
    
    }
    

    【讨论】:

    • 在 C 中,这与 Function(&variable1) 相同,但如果要指向 variable2,则需要调用 Function(&variable2)。我想做函数(pVariable),其中'double * pVariable'和变量在运行时被分配。
    • Paul,这不再是 C。这是 C#。这里的做法有所不同。
    • 尤达,这就是我在这里询问如何做的原因。抱歉,如果我的解释不清楚,但您的回答也无济于事。
    【解决方案4】:

    我不确定你为什么需要变量的地址。 Double 是值类型,存储在堆栈中。要通过引用将其传递给方法,只需使用 C# ref 关键字。
    从你提到的案例中,我个人更喜欢这样的:

    class Program
    {
        public class Refferenced<T> where T : struct 
        {
            public T Value { get; set; }
        }
    
        static void Main(string[] args)
        {
            Refferenced<double> x = new Refferenced<double>();
            Refferenced<double> y = new Refferenced<double>();
            y.Value = 2;
            x = y;
            x.Value = 5;
            Console.WriteLine(x.Value);
            Console.WriteLine(y.Value);
            y.Value = 7;
            Console.WriteLine(x.Value);
            Console.WriteLine(y.Value);
    
            Console.ReadKey();
        }
    


    它类似于 C# NullAble 类型。

    【讨论】:

    • 原因是我试图从图表工具中获得最大速度,并引用该工具在运行时绘制变化所需的类型值。每次调用绘图函数时,我都试图避免装箱/拆箱对象的开销。
    • double 的实例可能未存储在堆栈中。
    • @PaulG:如果您使用泛型,您将不会进行装箱/拆箱。您还应该记住,属性 getter 或 setter 是方法调用,因此如果您需要最佳性能,您可以用简单字段替换属性(值)。你也可以把这个通用类密封起来。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-22
    • 1970-01-01
    • 2016-12-27
    • 1970-01-01
    • 2023-02-09
    • 2011-05-04
    • 2022-11-23
    相关资源
    最近更新 更多