Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.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#_Colors_Struct_Ref - Fatal编程技术网

C# 传递颜色的策略(避免引用?)

C# 传递颜色的策略(避免引用?),c#,colors,struct,ref,C#,Colors,Struct,Ref,我在一个老化的windows应用程序中重构代码,我遇到了一种我不确定自己是否喜欢的模式:一个类具有全局颜色变量,如下所示: private Color myForegroundColor = Color.Azure; private Color myBackgroundColor = Color.Empty; // ...etc. public class ColorContainer { public UiSettingsContainer() { MyCo

我在一个老化的windows应用程序中重构代码,我遇到了一种我不确定自己是否喜欢的模式:一个类具有全局颜色变量,如下所示:

private Color myForegroundColor = Color.Azure;
private Color myBackgroundColor = Color.Empty;
// ...etc. 
public class ColorContainer
{
    public UiSettingsContainer()
    {
        MyColor = Color.Black;
        MyNextColor = Color.Blue;
        // ..etc...
    }

    public Color MyColor { get; private set; }
    // ...etc....
}
有很多这样的方法,它们通过ref传递给负责设置UI某些部分的方法

我推测
Color
是一个结构,因此每个颜色都由ref传递,以避免每次调用方法时都创建新的颜色副本。例如:

// Avoid creating a copy of myForgroundColor inside SetUpButton():
MyHelperClass.SetUpButton(ref myForegroundColor); 
我忍不住觉得在这个类和相关类中使用
ref
是不好的。这感觉像是一个“”,虽然我真的不知道为什么

我看到过一些关于类似问题的帖子,建议“使用一个包含颜色的类,然后将其作为值类型传递”,但目前还不完全清楚如何最好地做到这一点

我想做的是创建类似于以下内容的内容:

private Color myForegroundColor = Color.Azure;
private Color myBackgroundColor = Color.Empty;
// ...etc. 
public class ColorContainer
{
    public UiSettingsContainer()
    {
        MyColor = Color.Black;
        MyNextColor = Color.Blue;
        // ..etc...
    }

    public Color MyColor { get; private set; }
    // ...etc....
}
这会让我保留对颜色的控制,但对记忆的影响对我来说有点不清楚;如果我创建了这个类的一个实例,并将其传递给需要有关所包含颜色的信息的方法,那么在实现方法使用
color
(它是一个结构)时,会不会立即创建一个
颜色的副本

我假设这段代码会创建一个新的副本,从而降低效率,对吗

// Assumption: This creates a new copy of color in memory.
public void SetSomeColor(Color col){ 
    someComponent.color = col; 
}

// Calling it:
SetSomeColor(myColorContainerInstance.MyColor);
。。。这段代码只会使用现有结构?:

// Question: Does this avoid creating a new copy of MyColor in memory?
public void SetSomeColor(ColorContainer container){ 
    someComponent.color = container.MyColor; 
}

// Calling it:
SetSomeColor(myColorContainerInstance);
我目前倾向于一种类似于下面的解决方案,我在一个单独的类中收集颜色并稍微重新组织代码,但继续使用
ref
。但是,在这种情况下,
MyColor
必须是
ColorContainer
中的公共字段,这意味着我将无法控制谁可以设置它的值:

// Assumption: This creates a new copy of color in memory.
public void SetSomeColor(ref Color col){ 
    someComponent.color = col; 
}

// Calling it:
SetSomeColor(ref myColorContainerInstance.MyColor);

这是一个好的解决方案,还是有更好的策略来处理这样的资源?

整个事情闻起来就像是链接的第3部分和第4部分,所以

另一种解决方案是删除refs,并在需要时复制
Color
结构。结构本身不是太大(4个
byte
成员和4个
bool
成员),除非你调用每秒改变数百万次颜色的代码,否则所需的时间和内存不是问题。

对于这类事情,“slots”类比一直是我最喜欢的。每个方法参数(将赋值的右侧也视为参数)都是一个槽。为了调用一个方法(或处理一个赋值),每个插槽必须填充正确大小和“形状”(type)的内容

如果您的方法需要一个
ref Color
,那么您正在用指向内存中
Color
结构的任意大小的指针填充插槽。当然,我不是指C风格的指针,但它仍然是同一种类型的东西——它是一个数字,指示您打算使用的资源的位置,即使它没有在代码中表示出来。如果是
Color
(不带ref),则使用
Color
结构本身填充它

根据您编译的平台,您传递的值(用于颜色的按引用传递)的长度将为32或64位。color struct()本身的长度仅为32位(如果您使用的话,长度为64位),这使得这一命题不具有吸引力——使平均情况下的场景完全相同(就指针的副本数量和加载到堆栈上的内容的大小而言)按值传递结构-仅在64位结构/32位平台配对中更好,而仅在32位结构/64位平台配对中更差。即使尝试让结构使用同一实例,结构的实际值仍将复制到其目标插槽中

现在,在一个类中将颜色捆绑在一起(默认情况下通过引用传递)会稍微改变这张图片。如果您的类包含3种颜色,则其中包含96位(或192位)的颜色数据,最多传递64位信息,以在内存中找到该信息的正确“包”位置。即使在包装后,颜色仍将复制到其目标插槽中;但现在,我们增加了(加载字段)/(调用预解析的方法-属性访问)+ldfld/(调用运行时解析的方法-属性访问)+ldfld来实际获取值的开销。从性能的角度来看,这对您毫无帮助,除非您打算传递大量数据,然后不使用它


长话短说——除非有一些你想要实现的颜色信息的逻辑分组,否则不要麻烦了。当堆栈帧弹出时,堆栈上的值类型会立即被清除,因此,除非您的程序在系统总内存不足约8字节的情况下运行,否则使用by-ref方法实际上什么也得不到。颜色集合的包装类可能会使代码更干净/更好地分解,但不会提高性能。

通过
ref
传递结构通常是一件好事,除非(1)需要按值传递语义,或者(2)结构很小并且可以使用按值传递语义

如果经常希望将一些变量(可能是结构本身)作为一个组来处理,那么声明一个透明的结构类型来保存它们,然后通过
ref
传递它可能会有所帮助

请注意,按ref传递结构的成本与按值传递类引用的成本基本相同。编写一个类来保存结构,纯粹是为了避免使用
ref
参数,这不太可能是一个性能胜利。在某些情况下,有一个类型可能很有用

class MutableHolder<T>
{ public T Value; }
类可变持有人
{公共电视