Yanıtlar:
.NET'te, iki tür kategori vardır: başvuru türleri ve değer türleri .
Yapılar değer tipleridir ve sınıflar referans tipleridir .
Genel fark, bir referans türünün yığın üzerinde yaşadığı ve bir değer türünün satır içinde yaşadığı, yani değişkeniniz veya alanınızın nerede olduğu tanımlanmışsa olmasıdır.
Değer türü içeren bir değişken , değer türü değerinin tamamını içerir . Bir yapı için bu, değişkenin tüm yapılarıyla birlikte tüm yapıyı içerdiği anlamına gelir.
Referans türü içeren bir değişken , bir işaretçi veya gerçek değerin bulunduğu bellekte başka bir yere başvuru içerir .
Bunun bir faydası vardır:
Dahili olarak, referans türleri s işaretçiler olarak uygulanır ve bunu bilerek ve değişken atamanın nasıl çalıştığını bilerek başka davranış kalıpları vardır:
Değişkenleri veya alanları bildirirken, iki türün farkı şu şekildedir:
Her birinin kısa bir özeti:
Yalnızca Sınıflar:
Yalnızca Yapılar:
Hem Sınıflar hem de Yapılar:
c# struct memory overhead
ve Hans Passant'ın hayır olduğunu söyleyen bu cevabı buldum , durum da böyle değil. Yani ne yapmak yani?
class
örnekleri ise, hafızayı (çöp toplayıcı tarafından işlenen) yönetilen struct
değil .
.NET'te, yapı ve sınıf bildirimleri referans türleri ve değer türleri arasında ayrım yapar.
Bir referans türünün etrafından geçtiğinizde, sadece bir tane saklanır. Örneğe erişen tüm kodlar aynı örneğe erişiyor.
Bir değer türünden geçtiğinizde, her biri bir kopyadır. Tüm kod kendi kopyası üzerinde çalışıyor.
Bu bir örnekle gösterilebilir:
struct MyStruct
{
string MyProperty { get; set; }
}
void ChangeMyStruct(MyStruct input)
{
input.MyProperty = "new value";
}
...
// Create value type
MyStruct testStruct = new MyStruct { MyProperty = "initial value" };
ChangeMyStruct(testStruct);
// Value of testStruct.MyProperty is still "initial value"
// - the method changed a new copy of the structure.
Bir sınıf için bu farklı olurdu
class MyClass
{
string MyProperty { get; set; }
}
void ChangeMyClass(MyClass input)
{
input.MyProperty = "new value";
}
...
// Create reference type
MyClass testClass = new MyClass { MyProperty = "initial value" };
ChangeMyClass(testClass);
// Value of testClass.MyProperty is now "new value"
// - the method changed the instance passed.
Sınıflar hiçbir şey olamaz - başvuru null değerine işaret edebilir.
Yapılar asıl değerdir - boş olabilirler ama asla boş olamazlar. Bu nedenle yapıların her zaman parametresiz varsayılan bir kurucuları vardır - 'başlangıç değerine' ihtiyaçları vardır.
Yapılar ve Sınıflar Arasındaki Fark:
Microsoft'un Sınıf ve Yapı Arasındaki Seçimden ...
Genel bir kural olarak, bir çerçevedeki türlerin çoğunluğu sınıflar olmalıdır. Bununla birlikte, bir değer türünün özelliklerinin yapıların kullanımını daha uygun hale getirdiği bazı durumlar vardır.
✓ Sınıf yerine bir yapıyı göz önünde bulundurun:
- Tür örnekleri küçük ve genellikle kısa ömürlü ise veya genellikle diğer nesnelere gömülmüşse.
X Tür aşağıdaki özelliklerin tümüne sahip değilse bir yapıdan KAÇININ :
- Mantıksal olarak ilkel tiplere (int, double, vb.) Benzer tek bir değeri temsil eder.
- 16 baytın altında bir örnek boyutuna sahiptir.
- Değişmez. (değiştirilemez)
- Sık sık kutsanması gerekmeyecek.
Diğer cevaplarda açıklanan tüm farklılıklara ek olarak:
Tüm farkları açıklayan bir videonun peşindeyseniz, Bölüm 29 - C # Eğitimi - C # 'daki sınıflar ve yapılar arasındaki farkları kontrol edebilirsiniz .
Sınıf örnekleri yönetilen yığında saklanır. Bir örneği 'içeren' tüm değişkenler, öbek üzerindeki örneğe basitçe bir referanstır. Bir nesnenin bir yönteme iletilmesi, nesnenin kendisi değil referansın bir kopyasının iletilmesine neden olur.
Yapılar (teknik olarak, değer türleri) ilkel tipte olduğu gibi kullanıldığı her yerde depolanır. İçerik, çalışma zamanı tarafından herhangi bir zamanda ve özelleştirilmiş bir kopya oluşturucu çağrılmadan kopyalanabilir. Bir yönteme bir değer türünün iletilmesi, yine herhangi bir özelleştirilebilir kod çağrılmadan tüm değerin kopyalanmasını içerir.
Ayrım, C ++ / CLI adları ile daha iyi yapılır: "ref sınıfı" ilk olarak açıklandığı gibi bir sınıftır, "value sınıfı" ikinci olarak açıklandığı gibi bir sınıftır. C # tarafından kullanılan "class" ve "struct" anahtar sözcükleri basitçe öğrenilmesi gereken bir şeydir.
+------------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
| | Struct | Class |
+------------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
| Type | Value-type | Reference-type |
| Where | On stack / Inline in containing type | On Heap |
| Deallocation | Stack unwinds / containing type gets deallocated | Garbage Collected |
| Arrays | Inline, elements are the actual instances of the value type | Out of line, elements are just references to instances of the reference type residing on the heap |
| Aldel Cost | Cheap allocation-deallocation | Expensive allocation-deallocation |
| Memory usage | Boxed when cast to a reference type or one of the interfaces they implement, | No boxing-unboxing |
| | Unboxed when cast back to value type | |
| | (Negative impact because boxes are objects that are allocated on the heap and are garbage-collected) | |
| Assignments | Copy entire data | Copy the reference |
| Change to an instance | Does not affect any of its copies | Affect all references pointing to the instance |
| Mutability | Should be immutable | Mutable |
| Population | In some situations | Majority of types in a framework should be classes |
| Lifetime | Short-lived | Long-lived |
| Destructor | Cannot have | Can have |
| Inheritance | Only from an interface | Full support |
| Polymorphism | No | Yes |
| Sealed | Yes | When have sealed keyword |
| Constructor | Can not have explicit parameterless constructors | Any constructor |
| Null-assignments | When marked with nullable question mark | Yes (+ When marked with nullable question mark in C# 8+) |
| Abstract | No | When have abstract keyword |
| Member Access Modifiers| public, private, internal | public, protected, internal, protected internal, private protected |
+------------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
Yapı ve Sınıf
Bir yapı bir değer türüdür, bu nedenle yığın üzerinde depolanır, ancak bir sınıf bir referans türüdür ve yığın üzerinde saklanır.
Bir yapı miras ve polimorfizmi desteklemez, ancak bir sınıf her ikisini de destekler.
Varsayılan olarak, tüm yapı üyeleri herkese açıktır, ancak sınıf üyeleri varsayılan olarak özel niteliktedir.
Yapı bir değer türü olduğundan, bir struct nesnesine null atayamayız, ancak bir sınıf için durum böyle değildir.
Diğer cevaplara eklemek için kayda değer bir temel fark vardır ve bu da verilerin diziler içinde depolanmasıdır, çünkü bu performans üzerinde önemli bir etkisi olabilir.
Hafızada bir dizi yapı şöyle görünür
[struct][struct][struct][struct][struct][struct][struct][struct]
Halbuki bir dizi sınıf şöyle görünür
[pointer][pointer][pointer][pointer][pointer][pointer][pointer][pointer]
Bir sınıf dizisiyle, ilgilendiğiniz değerler dizi içinde değil, bellekte başka bir yerde saklanır.
Uygulamaların büyük çoğunluğu için bu fark gerçekten önemli değildir, ancak yüksek performans kodunda bu, bellek içindeki verilerin yerini etkileyecek ve CPU önbelleğinin performansı üzerinde büyük bir etkiye sahip olacaktır. Yapıları kullanabildiğiniz / kullanmanız gerektiğinde sınıfları kullanmak, CPU'daki önbellek hatalarının sayısını büyük ölçüde artıracaktır.
Modern CPU'nun yaptığı en yavaş şey sayıları ezmemek, bellekten veri almak ve L1 önbellek isabetini RAM'den veri okumaktan çok daha hızlıdır.
İşte test edebileceğiniz bazı kodlar. Makinemde, sınıf dizisi üzerinden yineleme, struct dizisinden ~ 3x daha uzun sürer.
private struct PerformanceStruct
{
public int i1;
public int i2;
}
private class PerformanceClass
{
public int i1;
public int i2;
}
private static void DoTest()
{
var structArray = new PerformanceStruct[100000000];
var classArray = new PerformanceClass[structArray.Length];
for (var i = 0; i < structArray.Length; i++)
{
structArray[i] = new PerformanceStruct();
classArray[i] = new PerformanceClass();
}
long total = 0;
var sw = new Stopwatch();
sw.Start();
for (var loops = 0; loops < 100; loops++)
for (var i = 0; i < structArray.Length; i++)
{
total += structArray[i].i1 + structArray[i].i2;
}
sw.Stop();
Console.WriteLine($"Struct Time: {sw.ElapsedMilliseconds}");
sw = new Stopwatch();
sw.Start();
for (var loops = 0; loops < 100; loops++)
for (var i = 0; i < classArray.Length; i++)
{
total += classArray[i].i1 + classArray[i].i2;
}
Console.WriteLine($"Class Time: {sw.ElapsedMilliseconds}");
}
Sadece tamamlamak için, Equals
yöntemi kullanırken, tüm sınıflar ve yapılar tarafından miras alınan başka bir fark vardır .
Diyelim ki bir sınıfımız ve bir yapımız var:
class A{
public int a, b;
}
struct B{
public int a, b;
}
ve Ana yöntemde 4 nesnemiz var.
static void Main{
A c1 = new A(), c2 = new A();
c1.a = c1.b = c2.a = c2.b = 1;
B s1 = new B(), s2 = new B();
s1.a = s1.b = s2.a = s2.b = 1;
}
Sonra:
s1.Equals(s2) // true
s1.Equals(c1) // false
c1.Equals(c2) // false
c1 == c2 // false
Böylece yapılar, noktalar gibi sayısal benzeri nesneler için uygundur (x ve y koordinatlarını kaydedin). Ve sınıflar başkaları için uygundur. 2 kişinin adı, boyu, kilosu aynı olsa bile, hala 2 kişidir.
Yeni başlayanlar için, bir yapı referanstan ziyade değere göre geçirilir. Yapılar göreceli olarak basit veri yapıları için iyidir, sınıflar ise polimorfizm ve kalıtım yoluyla mimari açıdan çok daha fazla esnekliğe sahiptir.
Diğerleri muhtemelen size benden daha fazla ayrıntı verebilir, ancak benim için çalıştığım yapı basit olduğunda yapılar kullanıyorum.
Erişim belirticisinin temel farkının yanı sıra, yukarıda bahsedilen az sayıda şeyin yanı sıra, referans ve değer hakkında daha net bir fikir verecek olan çıktıya sahip bir kod örneği ile yukarıda belirtilenlerin bir kısmı da dahil olmak üzere bazı önemli farkları eklemek istiyorum.
yapılar:
Sınıf:
Kod Örneği
static void Main(string[] args)
{
//Struct
myStruct objStruct = new myStruct();
objStruct.x = 10;
Console.WriteLine("Initial value of Struct Object is: " + objStruct.x);
Console.WriteLine();
methodStruct(objStruct);
Console.WriteLine();
Console.WriteLine("After Method call value of Struct Object is: " + objStruct.x);
Console.WriteLine();
//Class
myClass objClass = new myClass(10);
Console.WriteLine("Initial value of Class Object is: " + objClass.x);
Console.WriteLine();
methodClass(objClass);
Console.WriteLine();
Console.WriteLine("After Method call value of Class Object is: " + objClass.x);
Console.Read();
}
static void methodStruct(myStruct newStruct)
{
newStruct.x = 20;
Console.WriteLine("Inside Struct Method");
Console.WriteLine("Inside Method value of Struct Object is: " + newStruct.x);
}
static void methodClass(myClass newClass)
{
newClass.x = 20;
Console.WriteLine("Inside Class Method");
Console.WriteLine("Inside Method value of Class Object is: " + newClass.x);
}
public struct myStruct
{
public int x;
public myStruct(int xCons)
{
this.x = xCons;
}
}
public class myClass
{
public int x;
public myClass(int xCons)
{
this.x = xCons;
}
}
Çıktı
Struct Object'in başlangıç değeri: 10
Inside Struct Metodu Struct Object'in Inside Method değeri: 20
Method Object nesnesinin Yöntem çağrısı değeri: 10
Sınıf Nesnesinin başlangıç değeri: 10
Inside Class Metodu Class Object'in Inside Method değeri: 20
Class Object öğesinden Method call değeri: 20
Burada değere göre çağrı ile referansa göre çağrı arasındaki farkı açıkça görebilirsiniz.
Bir sınıfta bildirilen olayların, iş parçacığı güvenliğini sağlamak için + = ve - = erişimi bir kilitle otomatik olarak kilitlenir (bu, sınıfın türünde statik olaylar kilitlenir). Bir yapıda bildirilen olayların + = ve - = erişimi otomatik olarak kilitlenmez. Yalnızca başvuru türü ifadesine kilitleyebileceğinizden, bir yapıya ilişkin bir kilit (bu) çalışmaz.
Bir yapı örneği oluşturmak, çöp toplama (doğrudan veya dolaylı olarak bir başvuru türü örneği oluşturmadığı sürece) bir çöp toplama neden olamaz, ancak bir başvuru türü örneği oluşturmak çöp toplama neden olabilir.
Bir yapı her zaman yerleşik bir genel varsayılan yapıcıya sahiptir.
class DefaultConstructor
{
static void Eg()
{
Direct yes = new Direct(); // Always compiles OK
InDirect maybe = new InDirect(); // Compiles if constructor exists and is accessible
//...
}
}
Bu, bir yapının her zaman somutlaştırılabileceği anlamına gelirken, tüm kurucuları özel olabileceğinden bir sınıf olmayabilir.
class NonInstantiable
{
private NonInstantiable() // OK
{
}
}
struct Direct
{
private Direct() // Compile-time error
{
}
}
Bir yapının yıkıcısı olamaz. Yıkıcı sadece nesnenin geçersiz kılınmasıdır, kılık değiştirerek sonlandırın ve yapılar, değer türleri olan çöp toplama işlemine tabi değildir.
struct Direct
{
~Direct() {} // Compile-time error
}
class InDirect
{
~InDirect() {} // Compiles OK
}
And the CIL for ~Indirect() looks like this:
.method family hidebysig virtual instance void
Finalize() cil managed
{
// ...
} // end of method Indirect::Finalize
Bir yapı dolaylı olarak mühürlenir, bir sınıf değildir.
Bir yapı soyut olamaz, bir sınıf olabilir.
Bir yapı yapıcısında: base () öğesini çağıramazken açık taban sınıfı olmayan bir sınıf çağırabilir.
Bir yapı başka bir sınıfı genişletemez, bir sınıf da genişletebilir.
Bir yapı, bir sınıfın yapabileceği korumalı üyeleri (alanlar, yuvalanmış türler) bildiremez.
Bir yapı soyut işlev üyelerini bildiremez, soyut bir sınıf yapabilir.
Bir yapı sanal işlev üyelerini bildiremez, bir sınıf bunu yapabilir.
Bir yapı mühürlü fonksiyon üyelerini ilan edemez, bir sınıf yapabilir.
Bir yapı geçersiz kılma işlev üyelerini bildiremez, bir sınıf bunu yapabilir.
Bu kuralın tek istisnası, bir yapının System.Object, viz, Equals () ve GetHashCode () ve ToString () sanal yöntemlerini geçersiz kılabilmesidir.
Object
kutulu bir kopyasına bir referans tutabilecek, başlangıçta null gizli bir tür olan bir 'önbellek kutusu' yapı tipine sahip olsaydı (veya tanımlamayı mümkün kılar) .
Daha önce belirtildiği gibi: Sınıflar başvuru tipidir, Yapılar ise tüm sonuçları olan değer tipleridir.
Kuralın bir parçası olarak Çerçeve Tasarımı Yönergeleri, aşağıdaki durumlarda sınıflar yerine Yapılar kullanılmasını önerir:
Yöntemden birkaç sonuç döndürmeniz gerektiğinde ilginç bir "class vs struct" bulmaca durumu vardır: hangisini kullanacağınızı seçin. ValueTuple hikayesini biliyorsanız - Tuple (sınıf) 'dan daha etkili olması gerektiği için ValueTuple (struct) eklendiğini bilirsiniz. Ama rakamlarla ne anlama geliyor? İki test: biri 2 alana sahip yapı / sınıf, diğeri 8 alana sahip yapı / sınıf (4 sınıftan büyük boyutta işlemci keneleri açısından yapıdan daha etkili olmalı, ancak elbette GC yükü de dikkate alınmalıdır. ).
PS Özel durum 'sturct veya koleksiyonlu sınıf' için başka bir kriter var: https://stackoverflow.com/a/45276657/506147
BenchmarkDotNet=v0.10.10, OS=Windows 10 Redstone 2 [1703, Creators Update] (10.0.15063.726)
Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4
Frequency=3233540 Hz, Resolution=309.2586 ns, Timer=TSC
.NET Core SDK=2.0.3
[Host] : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT
Clr : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2115.0
Core : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT
Method | Job | Runtime | Mean | Error | StdDev | Min | Max | Median | Rank | Gen 0 | Allocated |
------------------ |----- |-------- |---------:|----------:|----------:|---------:|---------:|---------:|-----:|-------:|----------:|
TestStructReturn | Clr | Clr | 17.57 ns | 0.1960 ns | 0.1834 ns | 17.25 ns | 17.89 ns | 17.55 ns | 4 | 0.0127 | 40 B |
TestClassReturn | Clr | Clr | 21.93 ns | 0.4554 ns | 0.5244 ns | 21.17 ns | 23.26 ns | 21.86 ns | 5 | 0.0229 | 72 B |
TestStructReturn8 | Clr | Clr | 38.99 ns | 0.8302 ns | 1.4097 ns | 37.36 ns | 42.35 ns | 38.50 ns | 8 | 0.0127 | 40 B |
TestClassReturn8 | Clr | Clr | 23.69 ns | 0.5373 ns | 0.6987 ns | 22.70 ns | 25.24 ns | 23.37 ns | 6 | 0.0305 | 96 B |
TestStructReturn | Core | Core | 12.28 ns | 0.1882 ns | 0.1760 ns | 11.92 ns | 12.57 ns | 12.30 ns | 1 | 0.0127 | 40 B |
TestClassReturn | Core | Core | 15.33 ns | 0.4343 ns | 0.4063 ns | 14.83 ns | 16.44 ns | 15.31 ns | 2 | 0.0229 | 72 B |
TestStructReturn8 | Core | Core | 34.11 ns | 0.7089 ns | 1.4954 ns | 31.52 ns | 36.81 ns | 34.03 ns | 7 | 0.0127 | 40 B |
TestClassReturn8 | Core | Core | 17.04 ns | 0.2299 ns | 0.2150 ns | 16.68 ns | 17.41 ns | 16.98 ns | 3 | 0.0305 | 96 B |
Kod testi:
using System;
using System.Text;
using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Columns;
using BenchmarkDotNet.Attributes.Exporters;
using BenchmarkDotNet.Attributes.Jobs;
using DashboardCode.Routines.Json;
namespace Benchmark
{
//[Config(typeof(MyManualConfig))]
[RankColumn, MinColumn, MaxColumn, StdDevColumn, MedianColumn]
[ClrJob, CoreJob]
[HtmlExporter, MarkdownExporter]
[MemoryDiagnoser]
public class BenchmarkStructOrClass
{
static TestStruct testStruct = new TestStruct();
static TestClass testClass = new TestClass();
static TestStruct8 testStruct8 = new TestStruct8();
static TestClass8 testClass8 = new TestClass8();
[Benchmark]
public void TestStructReturn()
{
testStruct.TestMethod();
}
[Benchmark]
public void TestClassReturn()
{
testClass.TestMethod();
}
[Benchmark]
public void TestStructReturn8()
{
testStruct8.TestMethod();
}
[Benchmark]
public void TestClassReturn8()
{
testClass8.TestMethod();
}
public class TestStruct
{
public int Number = 5;
public struct StructType<T>
{
public T Instance;
public List<string> List;
}
public int TestMethod()
{
var s = Method1(1);
return s.Instance;
}
private StructType<int> Method1(int i)
{
return Method2(++i);
}
private StructType<int> Method2(int i)
{
return Method3(++i);
}
private StructType<int> Method3(int i)
{
return Method4(++i);
}
private StructType<int> Method4(int i)
{
var x = new StructType<int>();
x.List = new List<string>();
x.Instance = ++i;
return x;
}
}
public class TestClass
{
public int Number = 5;
public class ClassType<T>
{
public T Instance;
public List<string> List;
}
public int TestMethod()
{
var s = Method1(1);
return s.Instance;
}
private ClassType<int> Method1(int i)
{
return Method2(++i);
}
private ClassType<int> Method2(int i)
{
return Method3(++i);
}
private ClassType<int> Method3(int i)
{
return Method4(++i);
}
private ClassType<int> Method4(int i)
{
var x = new ClassType<int>();
x.List = new List<string>();
x.Instance = ++i;
return x;
}
}
public class TestStruct8
{
public int Number = 5;
public struct StructType<T>
{
public T Instance1;
public T Instance2;
public T Instance3;
public T Instance4;
public T Instance5;
public T Instance6;
public T Instance7;
public List<string> List;
}
public int TestMethod()
{
var s = Method1(1);
return s.Instance1;
}
private StructType<int> Method1(int i)
{
return Method2(++i);
}
private StructType<int> Method2(int i)
{
return Method3(++i);
}
private StructType<int> Method3(int i)
{
return Method4(++i);
}
private StructType<int> Method4(int i)
{
var x = new StructType<int>();
x.List = new List<string>();
x.Instance1 = ++i;
return x;
}
}
public class TestClass8
{
public int Number = 5;
public class ClassType<T>
{
public T Instance1;
public T Instance2;
public T Instance3;
public T Instance4;
public T Instance5;
public T Instance6;
public T Instance7;
public List<string> List;
}
public int TestMethod()
{
var s = Method1(1);
return s.Instance1;
}
private ClassType<int> Method1(int i)
{
return Method2(++i);
}
private ClassType<int> Method2(int i)
{
return Method3(++i);
}
private ClassType<int> Method3(int i)
{
return Method4(++i);
}
private ClassType<int> Method4(int i)
{
var x = new ClassType<int>();
x.List = new List<string>();
x.Instance1 = ++i;
return x;
}
}
}
}
Yapılar gerçek değerdir - boş olabilirler ama asla boş olamazlar
Bu doğrudur, ancak .NET 2 yapılarının Nullable sürümünü desteklediğini ve C # 'ın kullanımı kolaylaştırmak için bazı sözdizimsel şeker sağladığını da unutmayın.
int? value = null;
value = 1;
(object)(default(int?)) == null
, başka bir değer türüyle yapamayacağınız anlamına gelir , çünkü burada sadece şekerden daha fazlası vardır. Tek şeker int?
içindir Nullable<int>
.
İlkel bir değer türünün veya yapı türünün her değişkeni veya alanı, tüm alanları (genel ve özel) dahil olmak üzere bu türün benzersiz bir örneğini tutar. Buna karşılık, referans türlerinin değişkenleri veya alanları null tutabilir veya başka yerlerde depolanan ve herhangi bir sayıda başka referansın da mevcut olabileceği bir nesneye işaret edebilir. Bir yapının alanları, yığın üzerinde veya başka bir yığın nesnesinin parçası olabilen, o yapı türünün değişkeni veya alanı ile aynı yerde depolanır .
Bir ilkel değer türünün değişkenini veya alanını oluşturmak, onu varsayılan bir değerle oluşturur; yapı türünde bir değişken veya alan oluşturmak yeni bir örnek oluşturur ve buradaki tüm alanları varsayılan biçimde oluşturur. Bir başvuru türünün yeni bir örneğinin oluşturulması, içindeki tüm alanları varsayılan biçimde oluşturarak ve türe bağlı olarak isteğe bağlı ek kod çalıştırarak başlayacaktır.
İlkel türdeki bir değişkeni veya alanı diğerine kopyalamak değeri kopyalar. Bir değişken veya yapı türü alanını diğerine kopyalamak, önceki örneğin tüm alanlarını (genel ve özel) sonraki örneğe kopyalar. Bir değişken veya referans türü alanını diğerine kopyalamak, ikincisinin diğerine (varsa) aynı örneğe başvurmasına neden olur.
C ++ gibi bazı dillerde, bir türün semantik davranışının saklanma biçiminden bağımsız olduğunu, ancak bunun .NET için geçerli olmadığını unutmayın. Bir tür değişebilir değer semantiği uygularsa, bu türdeki bir değişkeni başka bir değişkene kopyalamak, ilkin özelliklerini ikinci tarafından başvurulan başka bir örneğe kopyalar ve onu değiştirmek için ikinci bir üyeyi kullanmak, bu ikinci örneğin değiştirilmesine neden olur. , ama ilk değil. Bir tür değişebilir referans anlambilimi uygularsa, bir değişkeni diğerine kopyalamak ve nesneyi değiştirmek için ikincisinin bir üyesini kullanmak ilk değişken tarafından başvurulan nesneyi etkiler; değişmez semantiğe sahip türler mutasyona izin vermez, bu nedenle kopyalamanın yeni bir örnek oluşturup oluşturmadığını veya birincisine başka bir başvuru oluşturup oluşturmayacağını anlamsal olarak fark etmez.
.NET'te, değer alanlarının, tüm alanlarının da benzer şekilde yapabilmesi şartıyla, yukarıdaki semantiklerden herhangi birini uygulaması mümkündür. Bununla birlikte, bir referans tipi sadece değişebilir referans anlambilimi veya değişmez anlambilimi uygulayabilir; Değişebilir referans türlerinin bulunduğu değer türleri, değişebilir referans semantiği veya garip karma semantik uygulamakla sınırlıdır.