'Var' kullanmak performansı etkiler mi?


230

Daha önce neden bu kadar çok örnek varanahtar kelimeyi kullandığımı gördüğüm bir soru sordum ve sadece anonim tipler için gerekli olmakla birlikte, yazma kodunu 'daha hızlı' / daha kolay ve 'sadece' yapmak için kullanmanın cevabını aldım.

Bu bağlantıyı takiben ("C # 3.0 - Var Objec değil") IL'devar doğru tipe kadar derlendiğini gördüm (makalenin ortasında göreceksiniz).

Benim sorum IL kodu varanahtar kelimeyi kullanarak ne kadar fazla yaparsa ve her yerde kullanılmışsa, kodun performansı üzerinde ölçülebilir bir seviyeye sahip olmaya yakın mı?


1
soru yıllar önce cevaplandı, sadece var karşı bir şey daha eklemek istedim - derleme zamanında çözülmesine rağmen, Visual Studio'nun "Tüm Referansları Bul" ve Resharper'ın "Kullanımları Bul" tarafından düzgün bir şekilde tespit edilmiyorsa, türün tüm kullanımlarını bulmak istiyorsanız - ve düzeltilmeyecek çünkü çok yavaş olacaktı.
KolA

@KolA ile bildirilen değişkenler varkesinlikle Visual Studio 2019'da "Tüm Referansları Bul" ile çalışır, bu yüzden kırılmışsa düzeltildi. Ancak Visual Studio 2012'ye kadar çalıştığını doğrulayabilirim, bu yüzden neden işe yaramadığını iddia ettiğinizden emin değilim.
Herohtar

@Herohtar "class X {} X GetX () {return new X ();} void UseX () {var x = GetX ();}" kodunu ve X için Tüm Referansları Bul, "var x = GetX ( ) "bit vurgulanmaz - en son VS2019'da şu andan itibaren, demek istediğim budur. Var yerine "X x = GetX ()" kullanırsanız
vurgulanır

1
@KolA Ah, ne demek istediğini anlıyorum - "Tüm Referansları Bul" seçeneğini kullandığınızda varreferans olarak görülmeyecektir . Üzerinde "Tüm başvurular Bul" kullanırsanız İlginçtir, bu açıklamada, bu olacak size başvurular göstermek (hala liste değildir gerçi deyimi). Ek olarak, imleç açıkken , aynı belgedeki tüm örnekleri vurgulayacaktır (veya tersi). XXvarXvarvarX
Herohtar

Yanıtlar:


316

varAnahtar kelime için fazladan IL kodu yoktur : elde edilen IL anonim olmayan türler için aynı olmalıdır. Derleyici kullanmak istediğiniz türü bulamadığı için bu IL'yi oluşturamazsa, bir derleyici hatası alırsınız.

Tek hile, vartürü manuel olarak ayarlayacaksanız, bir Arabirim veya üst öğe türü seçmiş olabileceğiniz tam bir tür çıkarır.


8 Yıl Sonra Güncelle

Anlayışım değiştikçe bunu güncellemem gerekiyor. Şimdi varbir yöntemin bir arabirim döndürdüğü durumlarda performansı etkilemenin mümkün olabileceğine inanıyorum , ancak tam bir tür kullanmış olacaksınız. Örneğin, bu yönteme sahipseniz:

IList<int> Foo()
{
    return Enumerable.Range(0,10).ToList();
}

Yöntemi çağırmak için şu üç kod satırını göz önünde bulundurun:

List<int> bar1 = Foo();
IList<int> bar = Foo();
var bar3 = Foo();

Üçü de beklendiği gibi derlenir ve çalıştırılır. Ancak, ilk iki satır tam olarak aynı değildir ve üçüncü satır ilk satırdan ziyade ikinci satırla eşleşir. İmzası Foo()an döndürmek IList<int>olduğundan, derleyici bar3değişkeni bu şekilde oluşturacaktır.

Performans açısından bakıldığında çoğunlukla fark etmezsiniz. Bununla birlikte, üçüncü hattın performansının birincinin performansı kadar hızlı olmayabileceği durumlar vardır . bar3Değişkeni kullanmaya devam ettikçe , derleyici yöntem çağrılarını aynı şekilde gönderemeyebilir.

Jitterin bu farkı silebileceğini (hatta muhtemelen) unutmayın, ancak garanti edilmez. Genel olarak, yine varde performans açısından bir faktör değildir. Kesinlikle bir dynamicdeğişken kullanmak gibi değil . Ama hiçbir zaman bir fark yaratmadığını söylemek abartılı olabilir.


23
IL aynı olmakla kalmaz , aynıdır. var i = 42; int i = 42 ile tam olarak aynı kodu derler;
Brian Rasmussen

15
@BrianRasmussen: Gönderinin eski olduğunu biliyorum, ama sanırım var i = 42;(infers type int) aynı değil long i = 42;. Bazı durumlarda, tür çıkarımıyla ilgili yanlış varsayımlar yapıyor olabilirsiniz. Değer uymuyorsa, bu zor / kenar durumu çalışma zamanı hatalarına neden olabilir. Bu nedenle, değerin açık bir türü olmadığında açık olmak iyi bir fikir olabilir. Yani, örneğin, var x = new List<List<Dictionary<int, string>()>()>()kabul edilebilir olurdu, ama var x = 42biraz belirsiz ve olarak yazılmalıdır int x = 42. Ama her biri kendi ...
Nelson Rothermel

50
@NelsonRothermel: Belirsiz var x = 42; değil . Tam sayı değişmezleri türdedir int. Eğer tam anlamıyla uzun yazmak istiyorsanız var x = 42L;.
Brian Rasmussen

6
Uhm IL C # için ne anlama geliyor? Gerçekten hiç duymadım.
puretppc

15
Farklı şekilde davranan 3 kod satırı örneğinizde, ilk satır derlenmez . Her ikisi de derleyen ikinci ve üçüncü satırlar aynı şeyi yapar. Eğer Fooa Listyerine bir a döndürülürse , IListüç satır da derlenir, ancak üçüncü satır ilk satır gibi davranır , ikinci satır gibi davranmaz .
16:48

72

Joel'in dediği gibi, derleyici derleme zamanında ne tür bir değişken olması gerektiğinde çalışır, etkili bir şekilde derleyicinin tuş vuruşlarını kaydetmek için yaptığı bir numaradır, örneğin

var s = "hi";

ile değiştirildi

string s = "hi";

herhangi bir IL oluşturulmadan önce derleyici tarafından . Oluşturulan IL, dize yazmış gibi tam olarak aynı olacaktır .


26

Kimse henüz reflektörden bahsetmediği gibi ...

Aşağıdaki C # kodunu derlerseniz:

static void Main(string[] args)
{
    var x = "hello";
    string y = "hello again!";
    Console.WriteLine(x);
    Console.WriteLine(y);
}

Sonra üzerinde reflektör kullanın, şunları elde edersiniz:

// Methods
private static void Main(string[] args)
{
    string x = "hello";
    string y = "hello again!";
    Console.WriteLine(x);
    Console.WriteLine(y);
}

Yani cevap açıkça çalışma zamanı performansı isabet yok!


17

Aşağıdaki yöntem için:

   private static void StringVsVarILOutput()
    {
        var string1 = new String(new char[9]);

        string string2 = new String(new char[9]);
    }

IL Çıkışı şöyledir:

        {
          .method private hidebysig static void  StringVsVarILOutput() cil managed
          // Code size       28 (0x1c)
          .maxstack  2
          .locals init ([0] string string1,
                   [1] string string2)
          IL_0000:  nop
          IL_0001:  ldc.i4.s   9
          IL_0003:  newarr     [mscorlib]System.Char
          IL_0008:  newobj     instance void [mscorlib]System.String::.ctor(char[])
          IL_000d:  stloc.0
          IL_000e:  ldc.i4.s   9
          IL_0010:  newarr     [mscorlib]System.Char
          IL_0015:  newobj     instance void [mscorlib]System.String::.ctor(char[])
          IL_001a:  stloc.1
          IL_001b:  ret
        } // end of method Program::StringVsVarILOutput

14

C # derleyicisi, varderleme zamanında değişkenin gerçek türünü belirler . Üretilen IL'de fark yoktur.


14

Net olmak gerekirse, bu tembel bir kodlama stili. Seçim göz önüne alındığında yerli türleri tercih ediyorum; Ben kod ve hata ayıklama zamanında olduğumu tam olarak ne yazıyorum ve okudum emin olmak için "gürültü" bu ekstra biraz alacak. * omuz silkme *


1
Bu sadece öznel görüşünüzdür ve performans hakkındaki soruya bir cevap değildir. Doğru cevap, performansı etkilememesidir. Yakına oy verdim
Anders

Bu, varperformansı hiç etkileyip etkilemediği sorusuna cevap vermez ; sadece insanların onu kullanması gerekip gerekmediğine dair fikrinizi belirtiyorsunuz.
Kahraman

Türü daha sonra değerden çıkarmak, örneğin int 5'ten flot 5.25'e geçmek kesinlikle performans sorunlarına neden olabilir. * omuz silkme *
ChrisH

Hayır, bu herhangi bir performans sorununa neden olmaz; intotomatik olarak dönüştürülemediği için bir tür değişkeni bekleyen herhangi bir yerde derleme hataları alırsınız float, ancak açıkça kullandığınızda intve sonrafloat . Her durumda, cevabınız hala "kullanmak varperformansı etkiler mi?" (özellikle üretilen IL açısından)
Herohtar

8

Ne okuduğunuzu tam olarak anladığınızı sanmıyorum. Doğru türüne derlenmiş edilirse, o zaman orada olduğunu fark. Bunu yaptığımda:

var i = 42;

Derleyici bir int biliyor ve ben yazmış gibi kod üretmek

int i = 42;

Bağlantı verdiğiniz gönderinin söylediği gibi, aynı türde derlenir . Bir çalışma zamanı denetimi veya ekstra kod gerektiren başka bir şey değildir. Derleyici sadece türün ne olması gerektiğini bulur ve bunu kullanır.


Doğru, ama ya sonra ben i = i - someVar ve someVar = 3.3. i şimdi Int. Sadece derleyiciye kusurları bulmaya başlaması için değil, aynı zamanda çalışma zamanı hatalarını veya süreci yavaşlatan tip dönüşümlerini de en aza indirmek için açık olmak daha iyidir. * shrug * Kendini tanımlamak için de kodu daha iyi yapar. Bunu çok uzun zamandır yapıyorum. Ben seçim verilen her zaman açık türleri ile "gürültülü" kodu alacak.
ChrisH

5

Var kullanmak için çalışma zamanı performans maliyeti yoktur. Yine de, derleyici türünü çıkarması gerektiği için derleyici bir performans maliyeti olduğundan şüphelenirim, ancak bu büyük olasılıkla ihmal edilebilir olacaktır.


10
RHS kendi türünü yine de hesaplamalıdır - derleyici uyumsuz türleri yakalar ve bir hata atar, bu yüzden orada gerçekten bir maliyet değil, bence.
Jimmy

3

Derleyici otomatik tip çıkarım yapabilirse, performansla ilgili herhangi bir sorun olmayacaktır. Bunların her ikisi de aynı kodu üretecek

var    x = new ClassA();
ClassA x = new ClassA();

ancak, türü dinamik olarak oluşturuyorsanız (LINQ ...) vartek sorunuz budur ve cezanın ne olduğunu söylemek için karşılaştırılacak başka bir mekanizma vardır.


3

Her zaman web makalelerinde veya kılavuzlarında var kelimesini kullanırım.

Çevrimiçi makalenin metin düzenleyicisinin genişliği azdır.

Bunu yazarsam:

SomeCoolNameSpace.SomeCoolClassName.SomeCoolSubClassName coolClass = new SomeCoolNameSpace.SomeCoolClassName.SomeCoolSubClassName();

Yukarıda oluşturulan ön kod metninin çok uzun olduğunu ve kutunun dışına aktığını göreceksiniz. Söz diziminin tamamını görmek için okuyucunun sağa kaydırması gerekir.

Bu yüzden her zaman web makale yazılarında var anahtar kelimesini kullanıyorum.

var coolClass = new SomeCoolNameSpace.SomeCoolClassName.SomeCoolSubClassName();

Oluşturulan tüm ön kod sadece ekrana sığar.

Uygulamada, nesneyi bildirmek için nadiren var kullanıyorum, nesneyi daha hızlı beyan etmek için zekaya güveniyorum.

Misal:

SomeCoolNamespace.SomeCoolObject coolObject = new SomeCoolNamespace.SomeCoolObject();

Ancak, nesneyi bir yöntemden döndürmek için, kodu daha hızlı yazmak için var kullanıyorum.

Misal:

var coolObject = GetCoolObject(param1, param2);

Öğrenciler için yazıyorsanız, kendi köpek mamasını yiyin ve sürekli olarak aynı "doğru" şekilde yazın. Öğrenciler genellikle% 100 kelimesi kelimesine ve kalbe alırlar ve yol boyunca aldıkları özensiz alışkanlıkları kullanmaya başlarlar. 0,02 $
ChrisH

1

"var" insanların sevdiği veya nefret ettiği şeylerden biridir (bölgeler gibi). Rağmen, bölgelerin aksine, anonim sınıflar oluştururken var kesinlikle gereklidir.

Bana göre var, doğrudan aşağıdaki gibi bir nesneyi yenilerken anlamlıdır:

var dict = new Dictionary<string, string>();

Bununla birlikte, kolayca yapabilirsiniz:

Dictionary<string, string> dict = yeni ve intellisense geri kalanı sizin için burada dolduracak.

Yalnızca belirli bir arabirimle çalışmak istiyorsanız, aradığınız yöntem doğrudan arabirimi döndürmediği sürece var kullanamazsınız.

Resharper, "var" ın her tarafını kullanıyor gibi görünüyor, bu da daha fazla insanı bu şekilde yapmaya zorlayabilir. Ancak, bir yöntemi çağırmanızın okunmasının daha zor olduğunu ve adla neyin geri döndüğünün açık olmadığını kabul ediyorum.

var'ın kendisi hiçbir şeyi yavaşlatmaz, ancak birçok insanın düşünmediği bir uyarı vardır. Bunu yaparsanız, var result = SomeMethod();bundan sonra kod, çeşitli yöntemleri veya özellikleri veya her şeyi çağıracağınız bir sonuç sonucunu bekler. Tanımını SomeMethod()başka bir tür olarak değiştirdiyse ancak yine de diğer kodun beklediği sözleşmeyi karşıladıysa, gerçekten kötü bir hata yarattınız (eğer birim / entegrasyon testi yoksa, elbette).


0

Bu duruma bağlıdır, eğer kullanmayı denerseniz, bu kod aşağıdaki.

İfade "NESNE" ye dönüştürülür ve performansı çok azaltır, ancak bu izole bir sorundur.

KODU:

public class Fruta
{
    dynamic _instance;

    public Fruta(dynamic obj)
    {
        _instance = obj;
    }

    public dynamic GetInstance()
    {
        return _instance;
    }
}

public class Manga
{
    public int MyProperty { get; set; }
    public int MyProperty1 { get; set; }
    public int MyProperty2 { get; set; }
    public int MyProperty3 { get; set; }
}

public class Pera
{
    public int MyProperty { get; set; }
    public int MyProperty1 { get; set; }
    public int MyProperty2 { get; set; }
}

public class Executa
{
    public string Exec(int count, int value)
    {
        int x = 0;
        Random random = new Random();
        Stopwatch time = new Stopwatch();
        time.Start();

        while (x < count)
        {
            if (value == 0)
            {
                var obj = new Pera();
            }
            else if (value == 1)
            {
                Pera obj = new Pera();
            }
            else if (value == 2)
            {
                var obj = new Banana();
            }
            else if (value == 3)
            {
                var obj = (0 == random.Next(0, 1) ? new Fruta(new Manga()).GetInstance() : new Fruta(new Pera()).GetInstance());
            }
            else
            {
                Banana obj = new Banana();
            }

            x++;
        }

        time.Stop();
        return time.Elapsed.ToString();
    }

    public void ExecManga()
    {
        var obj = new Fruta(new Manga()).GetInstance();
        Manga obj2 = obj;
    }

    public void ExecPera()
    {
        var obj = new Fruta(new Pera()).GetInstance();
        Pera obj2 = obj;
    }
}

ILSPY ile yukarıdaki sonuçlar.

public string Exec(int count, int value)
{
    int x = 0;
    Random random = new Random();
    Stopwatch time = new Stopwatch();
    time.Start();

    for (; x < count; x++)
    {
        switch (value)
        {
            case 0:
                {
                    Pera obj5 = new Pera();
                    break;
                }
            case 1:
                {
                    Pera obj4 = new Pera();
                    break;
                }
            case 2:
                {
                    Banana obj3 = default(Banana);
                    break;
                }
            case 3:
                {
                    object obj2 = (random.Next(0, 1) == 0) ? new Fruta(new Manga()).GetInstance() : new Fruta(new Pera()).GetInstance();
                    break;
                }
            default:
                {
                    Banana obj = default(Banana);
                    break;
                }
        }
    }
time.Stop();
return time.Elapsed.ToString();
}

Bu kodu yürütmek istiyorsanız aşağıdaki kodu kullanın ve zaman farkını elde edin.

        static void Main(string[] args)
    {
        Executa exec = new Executa();            
        int x = 0;
        int times = 4;
        int count = 100000000;
        int[] intanceType = new int[4] { 0, 1, 2, 3 };

        while(x < times)
        {                
            Parallel.For(0, intanceType.Length, (i) => {
                Console.WriteLine($"Tentativa:{x} Tipo de Instancia: {intanceType[i]} Tempo Execução: {exec.Exec(count, intanceType[i])}");
            });
            x++;
        }

        Console.ReadLine();
    }

Saygılarımızla

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.