Странно, но крутая новая фишка Visual Studio 2012 проскочила практически мимо официальных анонсов.

Visual Studio 2012 научилась компилировать проекты в несколько потоков.

Сами по себе и Visual Studio 2010, и msbuild поддерживали параллельное построение уже достаточно давно. Но по какой-то неизвестной причине работали они “из коробки” только для проектов Visual C++. Для C# приходилось использовать обходные пути, вроде прикручивания mbuild через External Tools.

В Visual Studio 2012 ограничение “только для C++” убрали. Так что не удивляйтесь, увидев для своего проекта в output загадочные числа в начале каждой строки:

1>------ Rebuild All started: Project: ClassLibrary1, Configuration: Debug Any CPU ------
2>------ Rebuild All started: Project: ClassLibrary2, Configuration: Debug Any CPU ------
2>  ClassLibrary2 -> C:Users...ClassLibrary2binDebugClassLibrary2.dll
1>  ClassLibrary1 -> C:Users...ClassLibrary1binDebugClassLibrary1.dll
========== Rebuild All: 2 succeeded, 0 failed, 0 skipped ==========

Количество одновременно собираемых проектов задается в Tools > Options > Projects and Solutions > Build and Run:

image

Опция глобальная, включена по умолчанию, и действует на все проекты (в том числе и на сконвертированные из предыдущих версий Visual Studio). Надеюсь, внезапно ускорившиеся билды и нелинейный output не станут для вас неприятным сюрпризом 😉

…по мотивам одной рассылки

Что выведет следующий код (при сборке под .NET 4.0 в 2010-й студии)?

using System;

class Base
{
   
public virtual bool Method1(bool value) { return true
; }
   
public virtual bool Method2(bool value) { return true
; }
}

class Derived : Base
{
   
public override bool Method1(bool value = true
)
    {
       
return
value;
    }

   
public override bool Method2(bool value = true
)
    {
       
return
Method1();
    }
}

class Program
{
   
static void Main(string
[] args)
    {
       
Derived a = new Derived
();

       
Console.WriteLine("Call to Method1, expected: True, got: {0}"
, a.Method1());
       
Console.WriteLine("Call to Method2, expected: True, got: {0}", a.Method2());
    }
}

Что выведет этот же код, если собрать его в Visual Studio 2012?

13. May 2012 · 4 comments · Categories: .NET 4.5, C#

Новый C# принес всего три новые фичи. Основаная – async/await уже достаточно разрекламирована. Вторая – изменение области видимости переменной цикла в foreach – скорее исправление ошибки в дизайне языка, чем полноценная фича. Третье изменение, которое затронуло непосредственно сам язык – это появление аттрибутов Caller Info.

Аттрибуты Caller Info – это три аттрибута: CallerFilePathAttribute, CallerLineNumberAttribute и CallerMemberNameAttribute. Их можно применить только к необязательным параметрам. Встретив вызов метода с одим из этих аттрибутов, компилятор попытается подставить информацию о вызывающем методе вместо значения параметра по умолчанию.

Есть два прямых применения этих аттрибутов. Первое – помощь в логгировании и трассировке. В примерах MSDN показано именно применение Caller Info вместе с System.Diagnostics.Trace:

Второе, и, наверное, более интересное примение – это упрощение реализации интерфейса INotifyPropertyChanged.

Стандартная реализация INotifyPropertyChanged в C# 4.0 выглядит так:

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    public string CustomerName
    {
        get
        {
            return this.customerNameValue;
        }

        set
        {
            if (value != this.customerNameValue)
            {
                this.customerNameValue = value;
                NotifyPropertyChanged("CustomerName");
            }
        }
    }

В C# 5.0 она упрощается до:

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public string CustomerName
    {
        get
        {
            return this.customerNameValue;
        }

        set
        {
            if (value != this.customerNameValue)
            {
                this.customerNameValue = value;
                NotifyPropertyChanged();
            }
        }
    }   

Без явного упоминания свойства по имени шанс поломать что-то при рефакторинге немного сокращается.

Да, ReSharper и раньше старался менять строковые константы при переименованиях свойств. И было несколько решений с лямбда-выражениями, вида NotifyPropertyChanged(() => this.CustomerName). Но встроенное в язык решение все-таки приятнее, чем обходные пути.

В .NET 4.5 многим стандарным классам были добавлены новые методы для поддержки async/await. В What’s New явно упомянут Asynchronous File I/O, но поиск выдает чуть больше новых методов.

Стандартные асинхронные методы появились так же в классах работы с сетью (dns/сокетами/почтой), базами данных и XML:

Namespace Type Methods
System.IO Stream и наследники FlushAsync
ReadAsync
WriteAsync
CopyToAsync
TextReader
StreamReader
StringReader
ReadAsync
ReadBlockAsync
ReadLineAsync
ReadToEndAsync
TextWriter
StringWriter
StreamWriter

WriteAsync
WriteLineAsync
FlushAsync

System.Threading SemaphoreSlim WaitAsync
System.Net Dns GetHostAddressesAsync
GetHostEntryAsync
HttpListener GetContextAsync
HttpListenerContext AcceptWebSocketAsync
HttpListenerRequest GetClientCertificateAsync
WebClient DownloadDataTaskAsync
DownloadFileTaskAsync
DownloadStringTaskAsync
OpenReadTaskAsync
OpenWriteTaskAsync
UploadDataTaskAsync
UploadFileTaskAsync
UploadStringTaskAsync
UploadValuesTaskAsync
System.Net.Mail SmtpClient SendMailAsync
System.Net.NetworkInformation IPGlobalProperties GetUnicastAddressesAsync
Ping SendPingAsync
System.Net.Security NegotiateStream
SslStream
AuthenticateAsClientAsync
AuthenticateAsServerAsync
System.Net.Sockets TcpClient ConnectAsync
TcpListener AcceptSocketAsync
AcceptTcpClientAsync
UdpClient ReceiveAsync
SendAsync
System.Net.WebSockets WebSocket
AspNetWebSocket
CloseAsync
CloseOutputAsync
ReceiveAsync
SendAsync
System.Data.Common DbCommand ExecuteNonQueryAsync
ExecuteReaderAsync
ExecuteScalarAsync
DbConnection OpenAsync
DbDataReader GetFieldValueAsync
IsDBNullAsync
NextResultAsync
ReadAsync
System.Data.SqlClient
(по сравнению с Common)
SqlBulkCopy WriteToServerAsync
SqlCommand ExecuteXmlReaderAsync
System.Net.Http HttpClient DeleteAsync
GetAsync
GetByteArrayAsync
GetStreamAsync
GetStringAsync
PostAsync
PutAsync
SendAsync
HttpContent CopyToAsync
LoadIntoBufferAsync
ReadAsByteArrayAsync
ReadAsStreamAsync
ReadAsStringAsync
System.ServiceModel.Description MetadataExchangeClient GetMetadataAsync
System.ServiceModel.Discovery AnnouncementClient AnnounceOfflineTaskAsync
AnnounceOnlineTaskAsync
System.Xml XmlReader GetValueAsync
MoveToContentAsync
ReadAsync
ReadContentAsAsync
ReadContentAsBase64Async
ReadContentAsBinHexAsync
ReadContentAsObjectAsync
ReadContentAsStringAsync
ReadElementContentAsAsync
ReadElementContentAsBase64Async
ReadElementContentAsBinHexAsync
ReadElementContentAsObjectAsync
ReadElementContentAsStringAsync
ReadInnerXmlAsync
ReadOuterXmlAsync
ReadValueChunkAsync
SkipAsync
XmlWriter FlushAsync
WriteAttributesAsync
WriteAttributeStringAsync
WriteBase64Async
WriteBinHexAsync
WriteCDataAsync
WriteCharEntityAsync
WriteCharsAsync
WriteCommentAsync
WriteDocTypeAsync
WriteElementStringAsync
WriteEndDocumentAsync
WriteEndElementAsync
WriteEntityRefAsync
WriteFullEndElementAsync
WriteNameAsync
WriteNmTokenAsync
WriteNodeAsync
WriteProcessingInstructionAsync
WriteQualifiedNameAsync
WriteRawAsync
WriteStartDocumentAsync
WriteStartElementAsync
WriteStringAsync
WriteSurrogateCharEntityAsync
WriteWhitespaceAsync
XmlDictionaryWriter WriteBase64Async
WriteValueAsync
XmlResolver и наследники GetEntityAsync