/// <summary> /// Merge another object representing a dependency into this object. /// </summary> /// <param name="config">Object to merge in.</param> private void Merge(ConfigObjC config) { foreach (string name in config.TypeNameSkipList) { if (!TypeNameSkipList.Contains(name)) { TypeNameSkipList.Add(name); } } foreach (string name in config.TypeNameWhiteList) { if (!TypeNameWhiteList.Contains(name)) { TypeNameWhiteList.Add(name); } } }
/** * Returns true if should generate binding for type * * Use the skip and white lists to control binding generation for individual types. * If a type is skipped then no binding will occur for any code element * ie: class, property, method, parameter etc that uses the skipped type. * * For simple binding scenarios type skipping will likely not be required but for more * complex situations it can greatly reduce the size and complexity of the generated bindings. */ public bool GenerateTypeBinding(string typename) { bool isSkipListed = false; bool isWhiteListed = true; // a type name will be delimited either by the end of the string // or by the occurence of any of the type name delimiter characters string typeNameDelimiters = ",<>[]& "; // is the type to be skipped? // we potentially skip if a matching typename occurs anywhere in the type signature, including as a generic type parameter. isSkipListed = TypeNameSkipList.Any(e => typename.IndexOf(e) != -1); // if type is not skip listed then use default whitelist state if (!isSkipListed) { return(isWhiteListed); } // check for whitelist override. isWhiteListed = false; StringBuilder sbTypeName = new StringBuilder(typename); foreach (var whiteTypeName in TypeNameWhiteList) { // replace each instance of white listed type with ?... int idx = 0; // note that some types, esp generics, may have the same type name repeated multiple times // so we need to scan the entire type name while (idx < sbTypeName.Length) { // look for any match idx = sbTypeName.ToString().IndexOf(whiteTypeName, idx); if (idx == -1) { break; } // we have a match but it may be a partial one: // e.g. System.Threading.Tasks.Task will match System.Threading.Tasks.TaskFactory // so we try and determine if our match is a full one. int idxEnd = idx + whiteTypeName.Length - 1; if (idxEnd + 1 < sbTypeName.Length) { // we can test the next character to see if indicates that the matched type // is part of a constructed type. string cursor = sbTypeName[idxEnd + 1].ToString(); // we need to match nested types in order to support // generic type definitions // e.g. System.Nullable`1<System.Nullable+T> if (cursor == "+") { // advance the end index to before next type delimiter idxEnd++; while (idxEnd + 1 < sbTypeName.Length) { cursor = sbTypeName[idxEnd + 1].ToString(); if (typeNameDelimiters.Contains(cursor)) { break; } idxEnd++; } } // if the next char is not a delimiter then we have a partial match // e.g. matching System.Action within System.Action`1 // and should continue our search after the current type else if (!typeNameDelimiters.Contains(cursor)) { // advance the index to the next type delimiter idx = idxEnd + 1; while (idx + 1 < sbTypeName.Length) { idx++; cursor = sbTypeName[idx].ToString(); if (typeNameDelimiters.Contains(cursor)) { break; } } continue; } } // replace all characters of match with a type neutral character for (; idx <= idxEnd; idx++) { sbTypeName[idx] = '?'; } idx++; } } // any white listed types have been neutralised. // if any skip listed types remain then the whitelisting has failed isSkipListed = TypeNameSkipList.Any(e => sbTypeName.ToString().IndexOf(e) != -1); isWhiteListed = !isSkipListed; return(isWhiteListed); }