1010 using System . Text ;
1111 using Microsoft . Build . Framework ;
1212 using Microsoft . Build . Utilities ;
13+ using Validation ;
1314
1415 public class AssemblyVersionInfo : Task
1516 {
@@ -112,7 +113,7 @@ public override bool Execute()
112113 {
113114 // attempt to use local codegen
114115 string fileContent = this . BuildCode ( ) ;
115- if ( fileContent != null )
116+ if ( fileContent is object )
116117 {
117118 Directory . CreateDirectory ( Path . GetDirectoryName ( this . OutputFile ) ) ;
118119 Utilities . FileOperationWithRetry ( ( ) => File . WriteAllText ( this . OutputFile , fileContent ) ) ;
@@ -179,6 +180,13 @@ private CodeTypeDeclaration CreateThisAssemblyClass()
179180 {
180181 switch ( pair . Value . Value )
181182 {
183+ case null :
184+ if ( pair . Value . EmitIfEmpty )
185+ {
186+ thisAssembly . Members . Add ( CreateField ( pair . Key , ( string ) null ) ) ;
187+ }
188+
189+ break ;
182190 case string stringValue :
183191 if ( pair . Value . EmitIfEmpty || ! string . IsNullOrEmpty ( stringValue ) )
184192 {
@@ -190,12 +198,12 @@ private CodeTypeDeclaration CreateThisAssemblyClass()
190198 thisAssembly . Members . Add ( CreateField ( pair . Key , boolValue ) ) ;
191199 break ;
192200
193- case long ticksValue :
194- thisAssembly . Members . AddRange ( CreateField ( pair . Key , ticksValue ) . ToArray ( ) ) ;
201+ case DateTime dateValue :
202+ thisAssembly . Members . AddRange ( CreateDateTimeField ( pair . Key , dateValue ) . ToArray ( ) ) ;
195203 break ;
196204
197205 default :
198- throw new NotImplementedException ( ) ;
206+ throw new NotSupportedException ( $ "Value type { pair . Value . Value . GetType ( ) . Name } as found for the \" { pair . Key } \" property is not supported." ) ;
199207 }
200208 }
201209
@@ -240,45 +248,15 @@ private static CodeMemberField CreateField<T>(string name, T value)
240248 } ;
241249 }
242250
243- private static IEnumerable < CodeTypeMember > CreateField ( string name , long ticks )
251+ private static IEnumerable < CodeTypeMember > CreateDateTimeField ( string name , DateTime value )
244252 {
245- if ( string . IsNullOrWhiteSpace ( name ) )
246- {
247- throw new ArgumentNullException ( nameof ( name ) ) ;
248- }
253+ Requires . NotNullOrEmpty ( name , nameof ( name ) ) ;
249254
250- // internal static System.DateTime GitCommitDate {{ get; }} = new System.DateTime({ticks}, System.DateTimeKind.Utc);");
251-
252- // For backing field name, try to use name with first char converted to lower case, or otherwise suffix with underscore.
253- string fieldName = null ;
254- var char0 = name [ 0 ] ;
255-
256- if ( char . IsUpper ( char0 ) )
257- {
258- fieldName =
259- name . Length == 1
260- ? new string ( char . ToLowerInvariant ( char0 ) , 1 )
261- : new string ( char . ToLowerInvariant ( char0 ) , 1 ) + name . Substring ( 1 ) ;
262- }
263- else
264- {
265- fieldName = name + "_" ;
266- }
267-
268- yield return new CodeMemberField ( typeof ( DateTime ) , fieldName )
269- {
270- Attributes = MemberAttributes . Private ,
271- InitExpression = new CodeObjectCreateExpression (
272- typeof ( DateTime ) ,
273- new CodePrimitiveExpression ( ticks ) ,
274- new CodePropertyReferenceExpression (
275- new CodeTypeReferenceExpression ( typeof ( DateTimeKind ) ) ,
276- nameof ( DateTimeKind . Utc ) ) )
277- } ;
255+ // internal static System.DateTime GitCommitDate => new System.DateTime({ticks}, System.DateTimeKind.Utc);");
278256
279257 var property = new CodeMemberProperty ( )
280258 {
281- Attributes = MemberAttributes . Assembly ,
259+ Attributes = MemberAttributes . Assembly | MemberAttributes . Static | MemberAttributes . Final ,
282260 Type = new CodeTypeReference ( typeof ( DateTime ) ) ,
283261 Name = name ,
284262 HasGet = true ,
@@ -287,9 +265,12 @@ private static IEnumerable<CodeTypeMember> CreateField(string name, long ticks)
287265
288266 property . GetStatements . Add (
289267 new CodeMethodReturnStatement (
290- new CodeFieldReferenceExpression (
291- null ,
292- fieldName ) ) ) ;
268+ new CodeObjectCreateExpression (
269+ typeof ( DateTime ) ,
270+ new CodePrimitiveExpression ( value . Ticks ) ,
271+ new CodePropertyReferenceExpression (
272+ new CodeTypeReferenceExpression ( typeof ( DateTimeKind ) ) ,
273+ nameof ( DateTimeKind . Utc ) ) ) ) ) ;
293274
294275 yield return property ;
295276 }
@@ -312,7 +293,7 @@ private static CodeAttributeDeclaration DeclareAttribute(Type attributeType, par
312293 public override bool Execute ( )
313294 {
314295 string fileContent = this . BuildCode ( ) ;
315- if ( fileContent != null )
296+ if ( fileContent is object )
316297 {
317298 Directory . CreateDirectory ( Path . GetDirectoryName ( this . OutputFile ) ) ;
318299 Utilities . FileOperationWithRetry ( ( ) => File . WriteAllText ( this . OutputFile , fileContent ) ) ;
@@ -330,7 +311,7 @@ public override bool Execute()
330311 public string BuildCode ( )
331312 {
332313 this . generator = this . CreateGenerator ( ) ;
333- if ( this . generator != null )
314+ if ( this . generator is object )
334315 {
335316 this . generator . AddComment ( FileHeaderComment ) ;
336317 this . generator . AddBlankLine ( ) ;
@@ -411,89 +392,83 @@ private void GenerateAssemblyAttributes()
411392
412393 if ( long . TryParse ( this . GitCommitDateTicks , out long gitCommitDateTicks ) )
413394 {
414- fields . Add ( "GitCommitDate" , ( gitCommitDateTicks , true ) ) ;
395+ fields . Add ( "GitCommitDate" , ( new DateTime ( gitCommitDateTicks , DateTimeKind . Utc ) , true ) ) ;
415396 }
416397
417- if ( this . AdditionalThisAssemblyFields != null && this . AdditionalThisAssemblyFields . Length > 0 )
398+ if ( this . AdditionalThisAssemblyFields is object )
418399 {
419400 foreach ( var item in this . AdditionalThisAssemblyFields )
420401 {
421- if ( item == null )
422- continue ;
423-
424402 var name = item . ItemSpec . Trim ( ) ;
425- var metaClone = item . CloneCustomMetadata ( ) ;
426- var meta = new Dictionary < string , string > ( metaClone . Count , StringComparer . OrdinalIgnoreCase ) ;
427- var iter = metaClone . GetEnumerator ( ) ;
428-
429- while ( iter . MoveNext ( ) )
403+ var meta = new Dictionary < string , string > ( item . MetadataCount , StringComparer . OrdinalIgnoreCase ) ;
404+ foreach ( string metadataName in item . MetadataNames )
430405 {
431- meta . Add ( ( string ) iter . Key , ( string ) iter . Value ) ;
406+ meta . Add ( metadataName , item . GetMetadata ( metadataName ) ) ;
432407 }
433408
434409 object value = null ;
435410 bool emitIfEmpty = false ;
436411
437- if ( meta . TryGetValue ( "String" , out var stringValue ) )
412+ if ( meta . TryGetValue ( "String" , out string stringValue ) )
438413 {
439414 value = stringValue ;
440- if ( meta . TryGetValue ( "EmitIfEmpty" , out var emitIfEmptyString ) )
415+ if ( meta . TryGetValue ( "EmitIfEmpty" , out string emitIfEmptyString ) )
441416 {
442417 if ( ! bool . TryParse ( emitIfEmptyString , out emitIfEmpty ) )
443418 {
444- this . Log . LogError ( "The value '{0 }' for EmitIfEmpty metadata for item '{1 }' in AdditionalThisAssemblyFields is not valid." , emitIfEmptyString , name ) ;
419+ this . Log . LogError ( $ "The value '{ emitIfEmptyString } ' for EmitIfEmpty metadata for item '{ name } ' in { nameof ( this . AdditionalThisAssemblyFields ) } is not valid.") ;
445420 continue ;
446421 }
447422 }
448423 }
449424
450- if ( meta . TryGetValue ( "Boolean" , out var boolText ) )
425+ if ( meta . TryGetValue ( "Boolean" , out string boolText ) )
451426 {
452- if ( value != null )
427+ if ( value is object )
453428 {
454- this . Log . LogError ( "The metadata for item '{0 }' in AdditionalThisAssemblyFields specifies more than one kind of value." , name ) ;
429+ this . Log . LogError ( $ "The metadata for item '{ name } ' in { nameof ( this . AdditionalThisAssemblyFields ) } specifies more than one kind of value.") ;
455430 continue ;
456431 }
457432
458- if ( bool . TryParse ( boolText , out var boolValue ) )
433+ if ( bool . TryParse ( boolText , out bool boolValue ) )
459434 {
460435 value = boolValue ;
461436 }
462437 else
463438 {
464- this . Log . LogError ( "The Boolean value '{0 }' for item '{1 }' in AdditionalThisAssemblyFields is not valid." , boolText , name ) ;
439+ this . Log . LogError ( $ "The Boolean value '{ boolText } ' for item '{ name } ' in AdditionalThisAssemblyFields is not valid.") ;
465440 continue ;
466441 }
467442 }
468443
469- if ( meta . TryGetValue ( "Ticks" , out var ticksText ) )
444+ if ( meta . TryGetValue ( "Ticks" , out string ticksText ) )
470445 {
471- if ( value != null )
446+ if ( value is object )
472447 {
473- this . Log . LogError ( "The metadata for item '{0 }' in AdditionalThisAssemblyFields specifies more than one kind of value." , name ) ;
448+ this . Log . LogError ( $ "The metadata for item '{ name } ' in { nameof ( this . AdditionalThisAssemblyFields ) } specifies more than one kind of value.") ;
474449 continue ;
475450 }
476451
477- if ( long . TryParse ( ticksText , out var ticksValue ) )
452+ if ( long . TryParse ( ticksText , out long ticksValue ) )
478453 {
479- value = ticksValue ;
454+ value = new DateTime ( ticksValue , DateTimeKind . Utc ) ;
480455 }
481456 else
482457 {
483- this . Log . LogError ( "The Ticks value '{0 }' for item '{1 }' in AdditionalThisAssemblyFields is not valid." , ticksText , name ) ;
458+ this . Log . LogError ( $ "The Ticks value '{ ticksText } ' for item '{ name } ' in { nameof ( this . AdditionalThisAssemblyFields ) } is not valid.") ;
484459 continue ;
485460 }
486461 }
487462
488- if ( value == null )
463+ if ( value is null )
489464 {
490- this . Log . LogWarning ( "Field '{0 }' in AdditionalThisAssemblyFields has no value and will be ignored." , name ) ;
465+ this . Log . LogWarning ( $ "Field '{ name } ' in { nameof ( this . AdditionalThisAssemblyFields ) } has no value and will be ignored.") ;
491466 continue ;
492467 }
493468
494469 if ( fields . ContainsKey ( name ) )
495470 {
496- this . Log . LogError ( "Field name '{0 }' in AdditionalThisAssemblyFields has already been defined." , name ) ;
471+ this . Log . LogError ( $ "Field name '{ name } ' in { nameof ( this . AdditionalThisAssemblyFields ) } is defined multiple times." ) ;
497472 continue ;
498473 }
499474
@@ -532,12 +507,12 @@ private void GenerateThisAssemblyClass()
532507 this . generator . AddThisAssemblyMember ( pair . Key , boolValue ) ;
533508 break ;
534509
535- case long ticksValue :
536- this . generator . AddThisAssemblyMember ( pair . Key , ticksValue ) ;
510+ case DateTime datetimeValue :
511+ this . generator . AddThisAssemblyMember ( pair . Key , datetimeValue ) ;
537512 break ;
538513
539514 default :
540- throw new NotImplementedException ( ) ;
515+ throw new NotSupportedException ( $ "Value type { pair . Value . Value . GetType ( ) . Name } as found for the \" { pair . Key } \" property is not supported." ) ;
541516 }
542517 }
543518
@@ -580,7 +555,7 @@ internal CodeGenerator()
580555
581556 internal abstract void AddThisAssemblyMember ( string name , bool value ) ;
582557
583- internal abstract void AddThisAssemblyMember ( string name , long ticks ) ;
558+ internal abstract void AddThisAssemblyMember ( string name , DateTime value ) ;
584559
585560 internal abstract void EndThisAssemblyClass ( ) ;
586561
@@ -601,7 +576,7 @@ protected void AddCodeComment(string comment, string token)
601576 {
602577 var sr = new StringReader ( comment ) ;
603578 string line ;
604- while ( ( line = sr . ReadLine ( ) ) != null )
579+ while ( ( line = sr . ReadLine ( ) ) is object )
605580 {
606581 this . codeBuilder . Append ( token ) ;
607582 this . codeBuilder . AppendLine ( line ) ;
@@ -626,9 +601,9 @@ internal override void AddThisAssemblyMember(string name, bool value)
626601 this . codeBuilder . AppendLine ( $ " static member internal { name } = { ( value ? "true" : "false" ) } ") ;
627602 }
628603
629- internal override void AddThisAssemblyMember ( string name , long ticks )
604+ internal override void AddThisAssemblyMember ( string name , DateTime value )
630605 {
631- this . codeBuilder . AppendLine ( $ " static member internal { name } = new System.DateTime({ ticks } L, System.DateTimeKind.Utc)") ;
606+ this . codeBuilder . AppendLine ( $ " static member internal { name } = new System.DateTime({ value . Ticks } L, System.DateTimeKind.Utc)") ;
632607 }
633608
634609 internal override void EmitNamespaceIfRequired ( string ns )
@@ -692,9 +667,9 @@ internal override void AddThisAssemblyMember(string name, bool value)
692667 this . codeBuilder . AppendLine ( $ " internal const bool { name } = { ( value ? "true" : "false" ) } ;") ;
693668 }
694669
695- internal override void AddThisAssemblyMember ( string name , long ticks )
670+ internal override void AddThisAssemblyMember ( string name , DateTime value )
696671 {
697- this . codeBuilder . AppendLine ( $ " internal static readonly System.DateTime { name } = new System.DateTime({ ticks } L, System.DateTimeKind.Utc);") ;
672+ this . codeBuilder . AppendLine ( $ " internal static readonly System.DateTime { name } = new System.DateTime({ value . Ticks } L, System.DateTimeKind.Utc);") ;
698673 }
699674
700675 internal override void EndThisAssemblyClass ( )
@@ -739,9 +714,9 @@ internal override void AddThisAssemblyMember(string name, bool value)
739714 this . codeBuilder . AppendLine ( $ " Friend Const { name } As Boolean = { ( value ? "True" : "False" ) } ") ;
740715 }
741716
742- internal override void AddThisAssemblyMember ( string name , long ticks )
717+ internal override void AddThisAssemblyMember ( string name , DateTime value )
743718 {
744- this . codeBuilder . AppendLine ( $ " Friend Shared ReadOnly { name } As System.DateTime = New System.DateTime({ ticks } L, System.DateTimeKind.Utc)") ;
719+ this . codeBuilder . AppendLine ( $ " Friend Shared ReadOnly { name } As System.DateTime = New System.DateTime({ value . Ticks } L, System.DateTimeKind.Utc)") ;
745720 }
746721
747722 internal override void EndThisAssemblyClass ( )
@@ -797,14 +772,14 @@ private bool TryReadKeyInfo(out string publicKey, out string publicKeyToken)
797772 publicKeyBytes = GetPublicKeyFromKeyContainer ( this . AssemblyKeyContainerName ) ;
798773 }
799774
800- if ( publicKeyBytes != null && publicKeyBytes . Length > 0 ) // If .NET 2.0 isn't installed, we get byte[0] back.
775+ if ( publicKeyBytes is object && publicKeyBytes . Length > 0 ) // If .NET 2.0 isn't installed, we get byte[0] back.
801776 {
802777 publicKey = ToHex ( publicKeyBytes ) ;
803778 publicKeyToken = ToHex ( CryptoBlobParser . GetStrongNameTokenFromPublicKey ( publicKeyBytes ) ) ;
804779 }
805780 else
806781 {
807- if ( publicKeyBytes != null )
782+ if ( publicKeyBytes is object )
808783 {
809784 this . Log . LogWarning ( "Unable to emit public key fields in ThisAssembly class because .NET 2.0 isn't installed." ) ;
810785 }
0 commit comments