public void SetMemberValue(IConceptInfo conceptInfo, object value) { PropertyInfo pi; FieldInfo fi; if ((pi = MemberInfo as PropertyInfo) != null) { try { pi.SetValue(conceptInfo, value, null); } catch (ArgumentException ae) { throw new FrameworkException( string.Format(CultureInfo.InvariantCulture, "Unable to convert property {0} in concept {1} from type {2} to type {3}", pi.Name, conceptInfo.GetType().FullName, pi.PropertyType.FullName, value != null ? value.GetType().FullName : "unknown"), ae); } } else if ((fi = MemberInfo as FieldInfo) != null) { try { fi.SetValue(conceptInfo, value); } catch (ArgumentException ae) { throw new FrameworkException( string.Format(CultureInfo.InvariantCulture, "Unable to convert property {0} in concept {1} from type {2} to type {3}", pi.Name, conceptInfo.GetType().FullName, pi.PropertyType.FullName, value != null ? value.GetType().FullName : "unknown"), ae); } } else { throw new FrameworkException( string.Format(CultureInfo.InvariantCulture, "Unexpected member type {0} for member {1}.", MemberInfo.MemberType, MemberInfo.Name)); } }
private bool ConteptsValueEqualOrBase(IConceptInfo newConcept, IConceptInfo existingConcept) { if (object.ReferenceEquals(newConcept, existingConcept)) { return(true); } else if (newConcept.GetKey() != existingConcept.GetKey()) { return(false); } else if (!newConcept.GetType().IsInstanceOfType(existingConcept)) { return(false); } else { var newConceptMemebers = ConceptMembers.Get(newConcept); foreach (ConceptMember member in newConceptMemebers) { if (member.IsKey) { continue; } if (!IsConceptMemberEqual(newConcept, existingConcept, member)) { return(false); } } } return(true); }
private ValueOrError <IConceptInfo> ParseMembers(ITokenReader tokenReader, IConceptInfo lastConcept, bool readingAReference) { IConceptInfo conceptInfo = (IConceptInfo)Activator.CreateInstance(ConceptInfoType); bool firstMember = true; bool lastPropertyWasInlineParent = false; bool lastConceptUsed = false; var listOfMembers = readingAReference ? Members.Where(m => m.IsKey) : Members.Where(m => m.IsParsable); foreach (ConceptMember member in listOfMembers) { var valueOrError = ReadMemberValue(member, tokenReader, lastConcept, firstMember, ref lastPropertyWasInlineParent, ref lastConceptUsed, readingAReference); if (valueOrError.IsError) { return(ValueOrError <IConceptInfo> .CreateError(string.Format(CultureInfo.InvariantCulture, "Cannot read the value of {0} in {1}. {2}", member.Name, ConceptInfoType.Name, valueOrError.Error))); } member.SetMemberValue(conceptInfo, valueOrError.Value); firstMember = false; } if (!lastConceptUsed && lastConcept != null) { return(ValueOrError <IConceptInfo> .CreateError(string.Format( "This concept cannot be enclosed within {0}. Trying to read {1}.", lastConcept.GetType().Name, ConceptInfoType.Name))); } return(ValueOrError <IConceptInfo> .CreateValue(conceptInfo)); }
private void OnMemberRead(ITokenReader iTokenReader, IConceptInfo conceptInfo, ConceptMember conceptMember, ValueOrError <object> valueOrError) { // have we reached a new keyword after target pos? if so, prevent further member parsing if (result.NextKeywordToken != null) { return; } var tokenReader = (TokenReader)iTokenReader; if (tokenReader.PositionInTokenList <= 0 || lastTokenBeforeTarget == null) { return; } var conceptType = conceptInfo.GetType(); var lastTokenRead = result.Tokens[tokenReader.PositionInTokenList - 1]; // track last tokens/members parsed before or at target if (lastTokenRead.PositionInDslScript <= lastTokenBeforeTarget.PositionInDslScript && !valueOrError.IsError) { result.LastTokenParsed[conceptType] = lastTokenRead; result.LastMemberReadAttempt[conceptType] = conceptMember; } // we are interested in those concepts whose member parsing stops at or after target position if (lastTokenRead.PositionInDslScript >= lastTokenBeforeTarget.PositionInDslScript && !result.ActiveConceptValidTypes.Contains(conceptType)) { result.ActiveConceptValidTypes.Add(conceptType); } }
private static string GetPropertyName <T>(Expression <Func <T, object> > referenceProperty, IConceptInfo checkValueType) { var memberExpression = referenceProperty.Body as MemberExpression; if (memberExpression == null) { throw new FrameworkException("Invalid FindByReference method argument: referenceProperty. The argument should be a lambda expression selecting a property of the class " + typeof(T).Name + ". For example: \"conceptInfo => conceptInfo.SomeProperty\"."); } var property = memberExpression.Member as PropertyInfo; if (property == null || memberExpression.Expression.NodeType != ExpressionType.Parameter) { throw new FrameworkException("Invalid FindByReference method argument: referenceProperty. The argument should be a lambda expression selecting a property of the class " + typeof(T).Name + ". For example: \"conceptInfo => conceptInfo.SomeProperty\"."); } if (!typeof(IConceptInfo).IsAssignableFrom(property.PropertyType)) { throw new FrameworkException("Invalid FindByReference method argument: referenceProperty. The selected property should be of type that implements IConceptInfo." + " Property '" + property.Name + "' is of type '" + property.PropertyType.Name + "'."); } if (!property.PropertyType.IsAssignableFrom(checkValueType.GetType())) { throw new FrameworkException("Invalid FindByReference method arguments: The selected property " + property.Name + " type '" + property.PropertyType.Name + "' does not match the given referenced concept '" + checkValueType.GetUserDescription() + "'."); } return(property.Name); }
/// <summary> /// Use only for generating an error details. Returns the concept's description ignoring possible null reference errors. /// </summary> public static string GetErrorDescription(this IConceptInfo ci) { if (ci == null) { return("<null>"); } var report = new StringBuilder(); report.Append(ci.GetType().FullName); foreach (var member in ConceptMembers.Get(ci)) { report.Append(" " + member.Name + "="); var memberValue = member.GetValue(ci); try { if (memberValue == null) { report.Append("<null>"); } else if (member.IsConceptInfo) { AppendMembers(report, (IConceptInfo)memberValue, SerializationOptions.KeyMembers, exceptionOnNullMember: false); } else { report.Append(memberValue.ToString()); } } catch (Exception ex) { report.Append("<" + ex.GetType().Name + ">"); } } return(report.ToString()); }
private static void ValidateNewConceptSameAsExisting(IConceptInfo newConcept, IConceptInfo existingConcept) { if (newConcept == existingConcept) { return; } if (newConcept.GetFullDescription() == existingConcept.GetFullDescription()) { return; } // The new concept is allowed to be a simple version (base class) of the existing concept, even if it is not the same. // This will allow some macro concepts to create simplified new concept that will be ignored if more specific version is already implemented. // Note: Unfortunately this logic should not simply be reversed to also ignore old concept if the new concept is a derivation of the old one, // because other macros might have already used the old concept to generate a different business logic. if (newConcept.GetType().IsAssignableFrom(existingConcept.GetType()) && newConcept.GetFullDescription() == existingConcept.GetFullDescriptionAsBaseConcept(newConcept.GetType())) { return; } throw new DslSyntaxException( "Concept with same key is described twice with different values." + "\r\nValue 1: " + existingConcept.GetFullDescription() + "\r\nValue 2: " + newConcept.GetFullDescription() + "\r\nSame key: " + newConcept.GetKey()); }
private static List<MethodInfo> GetPluginMethods(IConceptMacro conceptMacro, IConceptInfo conceptInfo) { var methods = conceptMacro.GetType().GetInterfaces() .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IConceptMacro<>) && i.GetGenericArguments().Single().IsAssignableFrom(conceptInfo.GetType())) .Select(i => i.GetMethod("CreateNewConcepts")) .ToList(); if (methods.Count == 0) throw new FrameworkException(string.Format( "Plugin {0} does not implement generic interface {1} that accepts argument {2}.", conceptMacro.GetType().FullName, typeof(IConceptMacro<>).FullName, conceptInfo.GetType().FullName)); return methods; }
/// <summary> /// Returns a string that fully describes the concept instance. /// The string contains concept's type name and all concept's properties. /// </summary> public static string GetFullDescription(this IConceptInfo ci) { StringBuilder desc = new StringBuilder(200); desc.Append(ci.GetType().FullName); desc.Append(' '); AppendMembers(desc, ci, SerializationOptions.AllMembers); return(desc.ToString()); }
public static string GetShortDescription(this IConceptInfo ci) { StringBuilder desc = new StringBuilder(100); desc.Append(ci.GetType().Name); desc.Append(" "); AppendMembers(desc, ci, SerializationOptions.KeyMembers); return(desc.ToString()); }
private static Type BaseConceptInfoType(IConceptInfo ci) { Type t = ci.GetType(); while (typeof(IConceptInfo).IsAssignableFrom(t.BaseType) && t.BaseType.IsClass) { t = t.BaseType; } return(t); }
public static Type BaseConceptInfoType(this IConceptInfo ci) { Type t = ci.GetType(); while (typeof(IConceptInfo).IsAssignableFrom(t.BaseType)) { t = t.BaseType; } return(t); }
private static List <MethodInfo> GetPluginMethods(IConceptDataMigration dataMigrationScript, IConceptInfo conceptInfo) { var methods = dataMigrationScript.GetType().GetInterfaces() .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IConceptDataMigration <>) && i.GetGenericArguments().Single().IsAssignableFrom(conceptInfo.GetType())) .Select(i => i.GetMethod("GenerateCode")) .ToList(); if (methods.Count == 0) { throw new FrameworkException(string.Format( "Plugin {0} does not implement generic interface {1} that accepts argument {2}.", dataMigrationScript.GetType().FullName, typeof(IConceptDataMigration <>).FullName, conceptInfo.GetType().FullName)); } return(methods); }
public NewConceptApplication(IConceptInfo conceptInfo, IConceptDatabaseDefinition conceptImplementation) { Id = Guid.Empty; ConceptInfo = conceptInfo; ConceptInfoTypeName = conceptInfo.GetType().AssemblyQualifiedName; ConceptInfoKey = conceptInfo.GetKey(); ConceptImplementation = conceptImplementation; ConceptImplementationType = conceptImplementation.GetType(); ConceptImplementationTypeName = ConceptImplementationType.AssemblyQualifiedName; ConceptImplementationVersion = GetVersionFromAttribute(ConceptImplementationType); }
/// <summary> /// Returns a string that describes the concept instance cast as a base concept. /// The string contains base concept's type name and the base concept's properties. /// </summary> public static string GetFullDescriptionAsBaseConcept(this IConceptInfo ci, Type baseConceptType) { if (!baseConceptType.IsAssignableFrom(ci.GetType())) { throw new FrameworkException($"{baseConceptType} is not assignable from {ci.GetUserDescription()}."); } StringBuilder desc = new StringBuilder(200); desc.Append(baseConceptType.FullName); desc.Append(" "); AppendMembers(desc, ci, SerializationOptions.AllMembers, false, baseConceptType); return(desc.ToString()); }
private static void AppendMember(StringBuilder text, IConceptInfo ci, ConceptMember member, bool exceptionOnNullMember) { object memberValue = member.GetValue(ci); if (memberValue == null) { if (exceptionOnNullMember) { throw new DslSyntaxException(ci, string.Format( "{0}'s property {1} is null. Info: {2}.", ci.GetType().Name, member.Name, ci.GetErrorDescription())); } else { text.Append("<null>"); } } else if (member.IsConceptInfo) { IConceptInfo value = (IConceptInfo)member.GetValue(ci); if (member.ValueType == typeof(IConceptInfo)) { text.Append(BaseConceptInfoType(value).Name).Append(":"); } AppendMembers(text, value, SerializationOptions.KeyMembers, exceptionOnNullMember); } else if (member.ValueType == typeof(string)) { text.Append(SafeDelimit(member.GetValue(ci).ToString())); } else { throw new FrameworkException(string.Format( "IConceptInfo member {0} of type {1} in {2} is not supported.", member.Name, member.ValueType.Name, ci.GetType().Name)); } }
public void Add(IConceptInfo concept) { Type conceptType = concept.GetType(); _subtypes.Add(conceptType); foreach (ConceptMember member in ConceptMembers.Get(concept)) { if (member.IsConceptInfo) { string referencedConceptKey = ((IConceptInfo)member.GetValue(concept)).GetKey(); _conceptsIndex.Add(referencedConceptKey, conceptType, member.Name, concept); } } }
private string ReportPreviousConcept(IConceptInfo conceptInfo) { var sb = new StringBuilder(); if (conceptInfo != null) { sb.AppendFormat("Previous concept: {0}", conceptInfo.GetUserDescription()).AppendLine(); var properties = conceptInfo.GetType().GetProperties().ToList(); properties.ForEach(it => sb.AppendFormat("Property {0} ({1}) = {2}", it.Name, it.PropertyType.Name, it.GetValue(conceptInfo, null) ?? "<null>") .AppendLine()); } return(sb.ToString()); }
// The new concept is allowed to be a simple version (base class) of the existing concept, even if it is not the same. // This will allow some macro concepts to create simplified new concept that will be ignored if more specific version is already implemented. // Note: Unfortunately this logic should not simply be reversed to also ignore old concept if the new concept is a derivation of the old one, // because other macros might have already used the old concept to generate a different business logic. private void ValidateNewConceptSameAsExisting(IConceptInfo newConcept, IConceptInfo existingConcept) { _validateDuplicateStopwatch.Start(); if (newConcept != existingConcept && newConcept.GetFullDescription() != existingConcept.GetFullDescription() && !(newConcept.GetType().IsAssignableFrom(existingConcept.GetType()) && newConcept.GetFullDescription() == existingConcept.GetFullDescriptionAsBaseConcept(newConcept.GetType()))) { throw new DslSyntaxException( "Concept with same key is described twice with different values." + "\r\nValue 1: " + existingConcept.GetFullDescription() + "\r\nValue 2: " + newConcept.GetFullDescription() + "\r\nSame key: " + newConcept.GetKey()); } _validateDuplicateStopwatch.Stop(); }
public static ConceptSyntaxNode CreateConceptSyntaxNode(this DslSyntax dslSyntax, IConceptInfo ci) { var conceptInfoType = ci.GetType(); var node = new ConceptSyntaxNode(dslSyntax.GetConceptType(conceptInfoType)); var members = ConceptMembers.Get(conceptInfoType); if (node.Parameters.Length != members.Length) { throw new InvalidOperationException( $"{nameof(ConceptSyntaxNode)} parameters count ({node.Parameters.Length})" + $" does not match {nameof(ConceptMembers)} count ({members.Length})."); } for (int m = 0; m < members.Length; m++) { object value = members[m].GetValue(ci); node.Parameters[m] = value; if (value == null) { node.Parameters[m] = null; } else if (value is string) { node.Parameters[m] = value; } else if (value is IConceptInfo referencedConceptInfo) { var referencedNode = CreateConceptSyntaxNode(dslSyntax, referencedConceptInfo); node.Parameters[m] = referencedNode; } else { var valueType = value?.GetType().Name ?? "null"; throw new ArgumentException($"Value type {valueType} is not expected in '{ci.GetUserDescription()}', parameter {members[m].Name}."); } } return(node); }
private static ConceptApplication NewConceptApplication( IConceptInfo conceptInfo, IConceptDatabaseDefinition conceptImplementation, Guid Id, string CreateQuery, ConceptApplication[] DependsOn, int OldCreationOrder) { return(new ConceptApplication { //ConceptInfo = conceptInfo, ConceptInfoTypeName = conceptInfo.GetType().AssemblyQualifiedName, ConceptInfoKey = conceptInfo.GetKey(), //ConceptImplementation = conceptImplementation, //ConceptImplementationType = conceptImplementation.GetType(), ConceptImplementationTypeName = conceptImplementation.GetType().AssemblyQualifiedName, //ConceptImplementationVersion = GetVersionFromAttribute(conceptImplementation.GetType()), Id = Id, CreateQuery = CreateQuery, DependsOn = DependsOn, OldCreationOrder = OldCreationOrder }); }
private static void AppendMembers(StringBuilder text, IConceptInfo ci, SerializationOptions serializationOptions, bool exceptionOnNullMember = false, Type asBaseConceptType = null) { IEnumerable<ConceptMember> members = ConceptMembers.Get(asBaseConceptType ?? ci.GetType()); if (serializationOptions == SerializationOptions.KeyMembers) members = members.Where(member => member.IsKey); bool firstMember = true; foreach (ConceptMember member in members) { string separator = member.IsKey ? "." : " "; if (!firstMember) text.Append(separator); firstMember = false; AppendMember(text, ci, member, exceptionOnNullMember); } }
private static Type BaseConceptInfoType(IConceptInfo ci) { Type t = ci.GetType(); while (typeof(IConceptInfo).IsAssignableFrom(t.BaseType) && t.BaseType.IsClass) t = t.BaseType; return t; }
private ValueOrError <IConceptInfo> ParseMembers(ITokenReader tokenReader, IConceptInfo useLastConcept, bool readingAReference, ref bool parsedFirstReferenceElement) { IConceptInfo conceptInfo = (IConceptInfo)Activator.CreateInstance(ConceptInfoType); bool firstMember = true; var listOfMembers = readingAReference ? Members.Where(m => m.IsKey) : Members.Where(m => m.IsParsable); var parentProperty = listOfMembers.LastOrDefault(member => member.IsParentNested) ?? (listOfMembers.First().IsConceptInfo ? listOfMembers.First() : null); if (useLastConcept != null && parentProperty == null) { return(ValueOrError <IConceptInfo> .CreateError($"This concept cannot be nested within {useLastConcept.GetType().Name}. Trying to read {ConceptInfoType.Name}.")); } foreach (ConceptMember member in listOfMembers) { if (!readingAReference) { parsedFirstReferenceElement = false; // Reset a reference elements group, that should separated by dot. } var valueOrError = ReadMemberValue(member, tokenReader, member == parentProperty ? useLastConcept : null, firstMember, ref parsedFirstReferenceElement, readingAReference); if (valueOrError.IsError) { return(ValueOrError <IConceptInfo> .CreateError(string.Format(CultureInfo.InvariantCulture, "Cannot read the value of {0} in {1}. {2}", member.Name, ConceptInfoType.Name, valueOrError.Error))); } member.SetMemberValue(conceptInfo, valueOrError.Value); firstMember = false; } return(ValueOrError <IConceptInfo> .CreateValue(conceptInfo)); }
private static void AppendMember(StringBuilder text, IConceptInfo ci, ConceptMember member, bool exceptionOnNullMember) { object memberValue = member.GetValue(ci); if (memberValue == null) if (exceptionOnNullMember) throw new DslSyntaxException(ci, string.Format( "{0}'s property {1} is null. Info: {2}.", ci.GetType().Name, member.Name, ci.GetErrorDescription())); else text.Append("<null>"); else if (member.IsConceptInfo) { IConceptInfo value = (IConceptInfo)member.GetValue(ci); if (member.ValueType == typeof(IConceptInfo)) text.Append(BaseConceptInfoType(value).Name).Append(":"); AppendMembers(text, value, SerializationOptions.KeyMembers, exceptionOnNullMember); } else if (member.ValueType == typeof(string)) text.Append(SafeDelimit(member.GetValue(ci).ToString())); else throw new FrameworkException(string.Format( "IConceptInfo member {0} of type {1} in {2} is not supported.", member.Name, member.ValueType.Name, ci.GetType().Name)); }
// Check if the data structure already contains a specific row permissions filter that is not rule-based. Such filter is not compatible with RowPermissionsPluginableFiltersInfo. private void CheckForIncompatibleSpecificRowPermissionsFilter(IDslModel existingConcepts, IConceptInfo newRowPermissionsFilter, RowPermissionsPluginableFiltersInfo conceptInfo) { IConceptInfo oldRowPermissions = existingConcepts.FindByKey(newRowPermissionsFilter.GetKey()); if (oldRowPermissions == null) { return; } string filterName; string newFilterExpression; string oldFilterExpression = null; if (newRowPermissionsFilter is RowPermissionsReadInfo newReadFilter) { filterName = RowPermissionsReadInfo.FilterName; newFilterExpression = newReadFilter.SimplifiedExpression; if (oldRowPermissions is RowPermissionsReadInfo oldReadFilter) { oldFilterExpression = oldReadFilter.SimplifiedExpression; } } else if (newRowPermissionsFilter is RowPermissionsWriteInfo newWriteFilter) { filterName = RowPermissionsWriteInfo.FilterName; newFilterExpression = newWriteFilter.SimplifiedExpression; if (oldRowPermissions is RowPermissionsWriteInfo oldWriteFilter) { oldFilterExpression = oldWriteFilter.SimplifiedExpression; } } else { throw new InvalidOperationException($"Unexpected {nameof(newRowPermissionsFilter)} type '{newRowPermissionsFilter.GetType()}'."); } if (oldFilterExpression == null || oldFilterExpression != newFilterExpression) { throw new DslSyntaxException(conceptInfo, "Cannot use row permissions rules or row permissions inheritance on " + conceptInfo.DataStructure.GetUserDescription() + " because it already contains a specific row permissions filter (" + filterName + ")." + " Use RowPermissions concept instead of the specific filter, to create rules-based row permissions."); } }
private ValueOrError<IConceptInfo> ParseMembers(ITokenReader tokenReader, IConceptInfo lastConcept, bool readingAReference) { IConceptInfo conceptInfo = (IConceptInfo)Activator.CreateInstance(ConceptInfoType); bool firstMember = true; bool lastPropertyWasInlineParent = false; bool lastConceptUsed = false; var listOfMembers = readingAReference ? Members.Where(m => m.IsKey) : Members.Where(m => m.IsParsable); foreach (ConceptMember member in listOfMembers) { var valueOrError = ReadMemberValue(member, tokenReader, lastConcept, firstMember, ref lastPropertyWasInlineParent, ref lastConceptUsed, readingAReference); if (valueOrError.IsError) return ValueOrError<IConceptInfo>.CreateError(string.Format(CultureInfo.InvariantCulture, "Cannot read the value of {0} in {1}. {2}", member.Name, ConceptInfoType.Name, valueOrError.Error)); member.SetMemberValue(conceptInfo, valueOrError.Value); firstMember = false; } if (!lastConceptUsed && lastConcept != null) return ValueOrError<IConceptInfo>.CreateError(string.Format( "This concept cannot be enclosed within {0}. Trying to read {1}.", lastConcept.GetType().Name, ConceptInfoType.Name)); return ValueOrError<IConceptInfo>.CreateValue(conceptInfo); }
public static ConceptMember[] Get(IConceptInfo conceptInfo) { return(Get(conceptInfo.GetType(), new Lazy <IConceptInfo>(() => conceptInfo))); }
public static ConceptMember[] Get(IConceptInfo conceptInfo) { return Get(conceptInfo.GetType(), new Lazy<IConceptInfo>(() => conceptInfo)); }
private static void AppendMembers(StringBuilder text, IConceptInfo ci, SerializationOptions serializationOptions, bool exceptionOnNullMember = false, Type asBaseConceptType = null) { IEnumerable <ConceptMember> members = ConceptMembers.Get(asBaseConceptType ?? ci.GetType()); if (serializationOptions == SerializationOptions.KeyMembers) { members = members.Where(member => member.IsKey); } bool firstMember = true; foreach (ConceptMember member in members) { string separator = member.IsKey ? "." : " "; if (!firstMember) { text.Append(separator); } firstMember = false; AppendMember(text, ci, member, exceptionOnNullMember); } }
private ValueOrError <object> ReadMemberValue(ConceptMember member, ITokenReader tokenReader, IConceptInfo useLastConcept, bool firstMember, ref bool parsedFirstReferenceElement, bool readingAReference) { try { if (member.IsStringType) { if (useLastConcept != null) { return(ValueOrError <object> .CreateError($"This concept cannot be nested within {useLastConcept.GetType().Name}. Trying to read {ConceptInfoType.Name}.")); } if (readingAReference && parsedFirstReferenceElement) { if (!tokenReader.TryRead(".")) { return(ValueOrError <object> .CreateError(string.Format( "Parent property and the following key value ({0}) must be separated with a dot. Expected \".\"", member.Name))); } } parsedFirstReferenceElement = true; // Legacy syntax: if (!readingAReference && member.IsKey && member.IsStringType && !firstMember) { if (tokenReader.TryRead(".")) { AddWarning($"Obsolete syntax: Remove '.' from {Keyword} statement. {((TokenReader)tokenReader).ReportPosition()}."); } } return(tokenReader.ReadText().ChangeType <object>()); } if (member.ValueType == typeof(IConceptInfo)) { if (useLastConcept != null) { return((object)useLastConcept); } else { return(ValueOrError <object> .CreateError($"Member of type IConceptInfo can only be nested within" + $" the referenced parent concept. It must be a first member or marked with {nameof(ConceptParentAttribute)}.")); } } if (useLastConcept != null && member.ValueType.IsInstanceOfType(useLastConcept)) { return((object)useLastConcept); } if (member.IsConceptInfo && firstMember && !readingAReference && Members.Count(m => m.IsParsable) == 1) { // This validation is not necessary for consistent parsing. It is enforced simply to avoid ambiguity for future concept overloads // when parsing similar concepts such as "Logging { AllProperties; }", "History { AllProperties; }" and "Persisted { AllProperties; }". var parentMembers = ConceptMembers.Get(member.ValueType).Where(m => m.IsParsable).ToArray(); if (parentMembers.Count() == 1 && parentMembers.Single().IsConceptInfo) { return(ValueOrError.CreateError($"{ConceptInfoHelper.GetKeywordOrTypeName(ConceptInfoType)} must be nested" + $" within the referenced parent concept {ConceptInfoHelper.GetKeywordOrTypeName(member.ValueType)}." + $" A single-reference concept that references another single-reference concept must always be used with nested syntax to avoid ambiguity.")); } } if (member.IsConceptInfo) { if (firstMember && member.ValueType == ConceptInfoType) { return(ValueOrError.CreateError(string.Format( "Recursive concept {0} cannot be used as a root because its parent property ({1}) must reference another concept. Use a non-recursive concept for the root and a derivation of the root concept with additional parent property as a recursive concept.", ConceptInfoHelper.GetKeywordOrTypeName(ConceptInfoType), member.Name))); } GenericParser subParser = new GenericParser(member.ValueType, ""); return(subParser.ParseMembers(tokenReader, useLastConcept, true, ref parsedFirstReferenceElement).ChangeType <object>()); } return(ValueOrError.CreateError(string.Format( "GenericParser does not support members of type \"{0}\". Try using string or implementation of IConceptInfo.", member.ValueType.Name))); } catch (DslSyntaxException ex) { return(ValueOrError <object> .CreateError(ex.Message)); } }
public void Add(IConceptInfo concept) { _conceptsByType.Add(concept.GetType(), concept); }
public static string GetKeywordOrTypeName(this IConceptInfo ci) { return(ci.GetKeyword() ?? ci.GetType().Name); }
/// <summary> /// Return value is null if IConceptInfo implementations does not have ConceptKeyword attribute. Such classes are usually used as a base class for other concepts. /// </summary> public static string GetKeyword(this IConceptInfo ci) { return(GetKeyword(ci.GetType())); }
public static Type BaseConceptInfoType(this IConceptInfo ci) { return(BaseConceptInfoType(ci.GetType())); }
public void SetMemberValue(IConceptInfo conceptInfo, object value) { PropertyInfo pi; FieldInfo fi; if ((pi = MemberInfo as PropertyInfo) != null) try { pi.SetValue(conceptInfo, value, null); } catch (ArgumentException ae) { throw new FrameworkException( string.Format(CultureInfo.InvariantCulture, "Unable to convert property {0} in concept {1} from type {2} to type {3}", pi.Name, conceptInfo.GetType().FullName, pi.PropertyType.FullName, value != null ? value.GetType().FullName : "unknown"), ae); } else if ((fi = MemberInfo as FieldInfo) != null) try { fi.SetValue(conceptInfo, value); } catch (ArgumentException ae) { throw new FrameworkException( string.Format(CultureInfo.InvariantCulture, "Unable to convert property {0} in concept {1} from type {2} to type {3}", pi.Name, conceptInfo.GetType().FullName, pi.PropertyType.FullName, value != null ? value.GetType().FullName : "unknown"), ae); } else throw new FrameworkException( string.Format(CultureInfo.InvariantCulture, "Unexpected member type {0} for member {1}.", MemberInfo.MemberType, MemberInfo.Name)); }
protected string ReportErrorContext(IConceptInfo conceptInfo, int index) { var sb = new StringBuilder(); sb.AppendLine(_dslSource.ReportError(index)); if (conceptInfo != null) { sb.AppendFormat("Previous concept: {0}", conceptInfo.GetUserDescription()).AppendLine(); var properties = conceptInfo.GetType().GetProperties().ToList(); properties.ForEach(it => sb.AppendFormat("Property {0} ({1}) = {2}", it.Name, it.PropertyType.Name, it.GetValue(conceptInfo, null) ?? "<null>") .AppendLine()); } return sb.ToString(); }
public static ConceptMember[] Get(IConceptInfo conceptInfo) { return(Get(conceptInfo.GetType(), conceptInfo)); }