public static string GenerateStandAloneThriftSpec(Type type, List <string> dependentSpecFiles) { var builder = new CodeBuilder(); builder.AppendLine(); builder.AppendLine("namespace csharp " + type.Namespace); builder.AppendLine(); var trackedTypes = new HashSet <Type>(); var tobetracked = new Queue <Type>(); foreach (var m in GetServiceCalls(type)) { var return_value_type = m.ReturnType.GetGenericArguments()[0]; var parameter_type = m.GetParameters()[0].ParameterType.GetGenericArguments()[0]; if (!IsDependentOfPrimitiveTypes(return_value_type) && !trackedTypes.Contains(return_value_type)) { tobetracked.Enqueue(return_value_type); trackedTypes.Add(return_value_type); } if (IsDependentOfPrimitiveTypes(parameter_type) || trackedTypes.Contains(parameter_type)) { continue; } tobetracked.Enqueue(parameter_type); trackedTypes.Add(parameter_type); } while (tobetracked.Count > 0) { var t = tobetracked.Dequeue(); foreach (var fld in t.GetFields().Where(fld => !IsDependentOfPrimitiveTypes(fld.FieldType) && !trackedTypes.Contains(fld.FieldType))) { if (fld.FieldType.IsGenericType) { foreach (var p in fld.FieldType.GetGenericArguments().Where(p => !IsDependentOfPrimitiveTypes(p) && !trackedTypes.Contains(p))) { tobetracked.Enqueue(p); trackedTypes.Add(p); } } else { tobetracked.Enqueue(fld.FieldType); trackedTypes.Add(fld.FieldType); } } } // dump types with dependency order var g = new TypeGraph(); foreach (var t in trackedTypes) { var v = g.CreateVertex(typeof(TypeVertex), (ulong)t.GetHashCode()); v.Owner = t; } foreach (var t in trackedTypes) { var fv = g.Vertices.First(v => v.Value.Owner == t); foreach (var fld in t.GetFields().Where(fld => !IsDependentOfPrimitiveTypes(fld.FieldType))) { if (fld.FieldType.IsGenericType) { foreach (var tv in from p in fld.FieldType.GetGenericArguments() where !IsDependentOfPrimitiveTypes(p) select g.Vertices.First(v => v.Value.Owner == p)) { tv.Value.ConnectTo <TypeEdge>(fv.Value); } } else { var tv = g.Vertices.First(v => v.Value.Owner == fld.FieldType); tv.Value.ConnectTo <TypeEdge>(fv.Value); } } } var traversal = new DAGTraverserSatisfied <TypeVertex, TypeEdge, TypeGraph>(true); traversal.Traverse(g, v => { builder.AppendLine("struct " + GetThriftTypeName(v.Owner)); builder.BeginBlock(); var idx = 0; foreach (var fld in v.Owner.GetFields()) { if (fld.GetCustomAttributes().Any(a => a is FieldAttribute)) { idx = ((FieldAttribute)fld.GetCustomAttributes().First(a => a is FieldAttribute)).index; } else { idx++; } builder.AppendLine(idx + ":" + GetThriftTypeName(fld.FieldType) + " " + fld.Name + ";"); } builder.EndBlock(); builder.AppendLine(); return(true); }, false, false); builder.AppendLine("service " + type.Name); builder.BeginBlock(); foreach (var m in GetServiceCalls(type)) { var return_value_type = m.ReturnType.GetGenericArguments()[0]; var parameter_type = m.GetParameters()[0].ParameterType.GetGenericArguments()[0]; var return_value_name = GetThriftTypeName(return_value_type); var parameter_name = GetThriftTypeName(parameter_type); builder.AppendLine(return_value_name + " " + m.Name + "(1: " + parameter_name + " req);"); } builder.EndBlock(); builder.AppendLine(); return(builder.ToString()); }