Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.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中数据结构(引用类型)的值行为#_C#_Struct - Fatal编程技术网

C# 结构c中数据结构(引用类型)的值行为#

C# 结构c中数据结构(引用类型)的值行为#,c#,struct,C#,Struct,据我所知,结构是值类型,这意味着它们在传递时会被复制。因此,如果你改变了一份副本,你只改变了那份副本,而不是原件,也不是可能存在的任何其他副本 但是,您可能有一个包含类列表的结构,您需要这些类的值行为,例如: private struct InitData { public string name; public float initialSpeed; public bool loop; public List<Settings> settings;

据我所知,结构是值类型,这意味着它们在传递时会被复制。因此,如果你改变了一份副本,你只改变了那份副本,而不是原件,也不是可能存在的任何其他副本

但是,您可能有一个包含类列表的结构,您需要这些类的值行为,例如:

private struct InitData {
    public string name;
    public float initialSpeed;
    public bool loop;
    public List<Settings> settings;
}

因此,由于每次生成列表的新实例似乎不是很合适,是否有任何方法可以实现数据结构内部的值行为,以处理具有值类型行为(表示列表、数组、向量等)的许多实例或引用?

,如@InBetween所述,如果复制包含引用的结构,则只复制引用,而不复制引用引用的对象

可变结构是可变的,因此一般避免它们是一个好主意。如果一个不可变的结构包含对一个可变对象的引用,它将像任何其他引用所传递的行为一样,也就是说,当你对对象进行了变异时,你必须考虑对象是否被共享,如果是,如果你想改变对象,或者改变副本。 避免出现任何问题的一个好方法是确保对象始终是不可变的,因此任何更改都需要创建一个副本。使用System.Collections.Immutable库的示例:

public class Settings
{
    //Should only contain immutable fields
    public int MyValue { get; }

    public Settings(int myValue) => MyValue = myValue;

    // Can contain helpers to create a mutated object
    public Settings WithMyValue(int newMyValue) => new Settings(newMyValue);
}
public struct InitData
{
    public string Name { get; }
    public float InitialSpeed { get; }
    public bool Loop { get; }
    public ImmutableList<Settings> Settings { get; }

    public InitData(string name, float initialSpeed, bool loop, ImmutableList<Settings> settings)
    {
        this.Name = name;
        this.InitialSpeed = initialSpeed;
        this.Loop = loop;
        this.Settings = settings;
    }

    public InitData(string name, float initialSpeed, bool loop, IEnumerable<Settings> settings)
        : this(name, initialSpeed, loop, settings.ToImmutableList())
    { }

    public InitData MutateSettings(Func<ImmutableList<Settings>, ImmutableList<Settings>> mutator) 
        => new InitData(Name, InitialSpeed, Loop, mutator(Settings));
}
公共类设置
{
//应仅包含不可变字段
公共int MyValue{get;}
公共设置(int myValue)=>myValue=myValue;
//可以包含用于创建变异对象的帮助器
公共设置WithMyValue(int newMyValue)=>新设置(newMyValue);
}
公共结构InitData
{
公共字符串名称{get;}
公共浮点初始速度{get;}
公共布尔循环{get;}
公共不可变列表设置{get;}
public InitData(字符串名、浮点initialSpeed、bool循环、不可变列表设置)
{
this.Name=Name;
此参数。初始速度=初始速度;
this.Loop=Loop;
this.Settings=设置;
}
公共InitData(字符串名称、浮点initialSpeed、布尔循环、IEnumerable设置)
:这(名称、初始速度、循环、设置.ToImmutableList())
{ }
公共InitData MutateSettings(Func mutator)
=>新的初始数据(名称、初始速度、循环、变量(设置));
}
如您所述,另一种选择是创建深度副本,例如:

public class Settings
{
    public int MyValue { get; set; }
    public Settings(int myValue) => MyValue = myValue;
    public Settings Clone() => new Settings(MyValue);
}
public struct InitData
{
    public string Name { get; }
    public float InitialSpeed { get; }
    public bool Loop { get; }
    public List<Settings> Settings { get; }

    public InitData(string name, float initialSpeed, bool loop, List<Settings> settings)
    {
        this.Name = name;
        this.InitialSpeed = initialSpeed;
        this.Loop = loop;
        Settings = settings;
    }

    public InitData Clone() => new InitData(Name, InitialSpeed, Loop, Settings.Select(s => s.Clone()).ToList());
}
公共类设置
{
公共int MyValue{get;set;}
公共设置(int myValue)=>myValue=myValue;
公共设置克隆()=>新设置(MyValue);
}
公共结构InitData
{
公共字符串名称{get;}
公共浮点初始速度{get;}
公共布尔循环{get;}
公共列表设置{get;}
public InitData(字符串名称、浮点初始速度、布尔循环、列表设置)
{
this.Name=Name;
此参数。初始速度=初始速度;
this.Loop=Loop;
设置=设置;
}
public InitData Clone()=>new InitData(名称、初始速度、循环、设置);
}
由于InitData是浅不可变的,所以它是值类型还是引用类型并不重要,但由于它不是深不可变的,所以每当需要一个不变的副本时,都需要克隆它

创建一个透明地创建深度副本的方法可能相当困难。运行时不知道对象是否是深度不可变的,因此它需要复制所有字段,并且有可能复制的内容超出预期。您还需要一些方法来处理循环引用。所以我不知道有哪种c风格的语言有这种功能


有一种方法使用序列化,比如深度副本,但我不推荐使用。

“如果对本主题感兴趣,请随时提问”-?因为当我重置de类值时,我会将类值设置为结构值,并且我不希望引用保留的值,我想要这些值本身,因为这样我将再次更改类值,并将其重置为初始值,我想做的次数是多少。这有意义吗?首先应该避免可变值类型。这就是说,一个结构的引用类型成员仍然是一个引用类型,并且将以引用类型的形式运行。这就是我的问题的本质,如果您知道一个包含许多类的元素的数据结构以值类型的形式运行会怎么样呢。这可能吗?所以,每次你想“打破引用”时都要创建一个新的类实例是最好的方法吗?值类型的行为就像值类型一样。引用类型的行为与引用类型的行为相同。你不能改变这一点。如果希望作为值类型的成员的引用类型的行为类似于值类型,则这是不可能的。但是如果您的值类型是不可变的,那么这就不是问题。我的建议是,如果使用值类型,请使它们不可变。如果您不能使用引用类型,那么除非有非常好的性能原因使使用值类型成为必要。感谢您提供如此详细的答案。2评论。1.-深度复制是我考虑的第一件事,因为我想“批量深度复制”一个包含我的示例的更大的类,但是一些unity类是不可序列化的,所以我不得不缩小范围。2.-在我的例子中,第一种方法的一个小麻烦是,由于我的设置类相当大,我需要方法来更改每个属性,并且重载构造函数来维护每个属性更改的先前实例值,以便在新的设置构造中传递它们。无论如何,实现值类型行为的方法非常酷。是的,如果你想改变一个大对象,这是一个问题。c#9计划使用记录和With表达式,这将使这更容易,请参阅
public class Settings
{
    public int MyValue { get; set; }
    public Settings(int myValue) => MyValue = myValue;
    public Settings Clone() => new Settings(MyValue);
}
public struct InitData
{
    public string Name { get; }
    public float InitialSpeed { get; }
    public bool Loop { get; }
    public List<Settings> Settings { get; }

    public InitData(string name, float initialSpeed, bool loop, List<Settings> settings)
    {
        this.Name = name;
        this.InitialSpeed = initialSpeed;
        this.Loop = loop;
        Settings = settings;
    }

    public InitData Clone() => new InitData(Name, InitialSpeed, Loop, Settings.Select(s => s.Clone()).ToList());
}