@@ -90,6 +90,11 @@ internal TypeAccessor(Type type) {
9090 ConstructorParameters . Add ( new ( parameter ) ) ;
9191 }
9292
93+ /*------------------------------------------------------------------------------------------------------------------------
94+ | Identify expected topic, and set MaybeCompatible if a corresponding property exists
95+ \-----------------------------------------------------------------------------------------------------------------------*/
96+ SetItemCompatibility ( ) ;
97+
9398 }
9499
95100 /*==========================================================================================================================
@@ -390,5 +395,62 @@ internal void SetPropertyValue(object target, string propertyName, object? value
390395 internal void SetMethodValue ( object target , string methodName , object ? value , bool allowConversion = false )
391396 => SetValue ( target , methodName , value , allowConversion ) ;
392397
398+ /*==========================================================================================================================
399+ | METHOD: SET ITEM COMPATIBILITY
400+ \-------------------------------------------------------------------------------------------------------------------------*/
401+ /// <summary>
402+ /// Determines if each member corresponds to a compatible or convertible member of a corresponding <see cref="Topic"/>.
403+ /// </summary>
404+ /// <remarks>
405+ /// The <see cref="SetItemCompatibility"/> method applies basic assumptions to identify the corresponding <see cref=
406+ /// "Topic"/> and whether or not any matching parameters or members are compatible with members of that <see cref="Topic"
407+ /// />. See <see cref="ItemMetadata.MaybeCompatible"/> for more details.
408+ /// </remarks>
409+ private void SetItemCompatibility ( ) {
410+
411+ /*------------------------------------------------------------------------------------------------------------------------
412+ | Only attempt to detect compatibility for model types, not for topics.
413+ >-------------------------------------------------------------------------------------------------------------------------
414+ | We expect mapping to topics to typically use e.g. Attributes or References, which will automatically marshal through
415+ | properties if appropriate.
416+ \-----------------------------------------------------------------------------------------------------------------------*/
417+ if ( typeof ( Topic ) . IsAssignableFrom ( Type ) ) {
418+ return ;
419+ }
420+
421+ /*------------------------------------------------------------------------------------------------------------------------
422+ | Identify corresponding topic type
423+ >-------------------------------------------------------------------------------------------------------------------------
424+ | Assuming a model follows the convention {ContentType}TopicViewModel or {ContentType}ViewModel, find a corresponding
425+ | Topic named {ContentType}. If this cannot be found, fall back to Topic.
426+ \-----------------------------------------------------------------------------------------------------------------------*/
427+ var impliedContentType = Type . Name
428+ . Replace ( "TopicViewModel" , "" , StringComparison . OrdinalIgnoreCase )
429+ . Replace ( "ViewModel" , "" , StringComparison . OrdinalIgnoreCase ) ;
430+ var topicType = TopicFactory . TypeLookupService . Lookup ( impliedContentType ) ?? typeof ( Topic ) ;
431+ var topicAccessor = TypeAccessorCache . GetTypeAccessor ( topicType ) ;
432+
433+ /*------------------------------------------------------------------------------------------------------------------------
434+ | Detect compatibility
435+ >-------------------------------------------------------------------------------------------------------------------------
436+ | If the Topic contains a property named {Name} or a method named Get{Name}, and that member's type is either compatible
437+ | or convertible, then set MaybeCompatible to true.
438+ \-----------------------------------------------------------------------------------------------------------------------*/
439+ foreach ( var member in ConstructorParameters . Cast < ItemMetadata > ( ) . Union ( _members . Values ) ) {
440+ var attributeKey = member . Configuration . AttributeKey ;
441+ var topicMember = topicAccessor . GetMember ( attributeKey ) ?? topicAccessor . GetMember ( $ "Get{ attributeKey } ") ;
442+ if ( topicMember is null ) {
443+ continue ;
444+ }
445+ else if ( member . IsConvertible && topicMember . Type == typeof ( string ) ) {
446+ member . MaybeCompatible = true ;
447+ }
448+ else if ( member . Type . IsAssignableFrom ( topicMember . Type ) ) {
449+ member . MaybeCompatible = true ;
450+ }
451+
452+ }
453+ }
454+
393455 } //Class
394456} //Namespace
0 commit comments