using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
public class Program {
static void Main(string[] args)
{
object x = 2;
var a = new A();
a.Val = x;
a.array = new A[3] { a, new A() { Val = "a"}, null};
var b = new A();
b.Val = x;
b.array = new A[3] { b, new A() { Val = "a"}, null};
a.array[2] = b;
b.array[2] = b;
Console.WriteLine(string.Join("\n", FindStringValues(a).ToArray()));
}
public class A {
public A[] array {get;set;}
public object Val {get;set;}
}
private static IEnumerable<string> FindStringValues(object obj) {
return _FindStringValues(obj, new List<object>());
}
private static IEnumerable<string> _FindStringValues(object obj, IList<object> visitedObjects)
{
if (obj == null)
yield break;
// Console.WriteLine(string.Join("; ", visitedObjects.Select(i => i.ToString()).ToArray()));
if (visitedObjects.Any(item => Object.ReferenceEquals(item, obj)))
yield break;
if (!(obj is string))
visitedObjects.Add(obj);
Type type = obj.GetType();
if (type == typeof(string)) {
yield return (obj).ToString();
yield break;
}
if (typeof(IEnumerable).IsAssignableFrom(type))
{
var array = obj as IEnumerable;
foreach (var item in array)
foreach (var str in _FindStringValues(item, visitedObjects))
yield return str;
yield break;
}
if (type.IsClass)
{
FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (FieldInfo field in fields)
{
object item = field.GetValue(obj);
if (item == null)
continue;
foreach (var str in _FindStringValues(item, visitedObjects))
yield return str;
}
yield break;
}
}
}
dXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uTGlucTsKdXNpbmcgU3lzdGVtLkNvbGxlY3Rpb25zOwp1c2luZyBTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYzsKdXNpbmcgU3lzdGVtLlJlZmxlY3Rpb247CgpwdWJsaWMgY2xhc3MgUHJvZ3JhbSB7CiAgICBzdGF0aWMgdm9pZCBNYWluKHN0cmluZ1tdIGFyZ3MpCiAgICB7CiAgICAgICAgb2JqZWN0IHggPSAyOwogICAgICAgIHZhciBhID0gbmV3IEEoKTsKICAgIAlhLlZhbCA9IHg7CiAgICAJYS5hcnJheSA9IG5ldyBBWzNdIHsgYSwgbmV3IEEoKSB7IFZhbCA9ICJhIn0sIG51bGx9OwogICAgCiAgICAKICAgICAgICB2YXIgYiA9IG5ldyBBKCk7CiAgICAgICAgYi5WYWwgPSB4OwogICAgCWIuYXJyYXkgPSBuZXcgQVszXSB7IGIsIG5ldyBBKCkgeyBWYWwgPSAiYSJ9LCBudWxsfTsKICAgICAgICAKICAgICAgICBhLmFycmF5WzJdID0gYjsKICAgICAgICBiLmFycmF5WzJdID0gYjsKICAgIAkKICAgIAlDb25zb2xlLldyaXRlTGluZShzdHJpbmcuSm9pbigiXG4iLCBGaW5kU3RyaW5nVmFsdWVzKGEpLlRvQXJyYXkoKSkpOwogICAgfQogICAgCiAgICBwdWJsaWMgY2xhc3MgQSB7CiAgICAJcHVibGljIEFbXSBhcnJheSB7Z2V0O3NldDt9CiAgICAJcHVibGljIG9iamVjdCBWYWwge2dldDtzZXQ7fQogICAgfQogICAgCiAgICBwcml2YXRlIHN0YXRpYyBJRW51bWVyYWJsZTxzdHJpbmc+IEZpbmRTdHJpbmdWYWx1ZXMob2JqZWN0IG9iaikgewogICAgCXJldHVybiBfRmluZFN0cmluZ1ZhbHVlcyhvYmosIG5ldyBMaXN0PG9iamVjdD4oKSk7CiAgICB9CiAgICAKICAgIHByaXZhdGUgc3RhdGljIElFbnVtZXJhYmxlPHN0cmluZz4gX0ZpbmRTdHJpbmdWYWx1ZXMob2JqZWN0IG9iaiwgSUxpc3Q8b2JqZWN0PiB2aXNpdGVkT2JqZWN0cykKICAgIHsJCiAgICAgICAgaWYgKG9iaiA9PSBudWxsKQogICAgICAgICAgICB5aWVsZCBicmVhazsKICAgICAgICAgICAgCiAgICAgICAvLyBDb25zb2xlLldyaXRlTGluZShzdHJpbmcuSm9pbigiOyAiLCB2aXNpdGVkT2JqZWN0cy5TZWxlY3QoaSA9PiBpLlRvU3RyaW5nKCkpLlRvQXJyYXkoKSkpOwogICAgICAgIGlmICh2aXNpdGVkT2JqZWN0cy5BbnkoaXRlbSA9PiBPYmplY3QuUmVmZXJlbmNlRXF1YWxzKGl0ZW0sIG9iaikpKQogICAgICAgICAgICB5aWVsZCBicmVhazsKICAgICAgICAgICAgCiAgICAgICAgaWYgKCEob2JqIGlzIHN0cmluZykpCiAgICAgICAgICAgIHZpc2l0ZWRPYmplY3RzLkFkZChvYmopOwogICAgICAgIAogICAgICAgIFR5cGUgdHlwZSA9IG9iai5HZXRUeXBlKCk7CiAgICAgICAgCiAgICAgICAgaWYgKHR5cGUgPT0gdHlwZW9mKHN0cmluZykpIHsKCQkJeWllbGQgcmV0dXJuIChvYmopLlRvU3RyaW5nKCk7CiAgICAgICAgICAgIHlpZWxkIGJyZWFrOwoJCX0KICAgICAgICAKICAgICAgICBpZiAodHlwZW9mKElFbnVtZXJhYmxlKS5Jc0Fzc2lnbmFibGVGcm9tKHR5cGUpKQoJCXsKCQkJdmFyIGFycmF5ID0gb2JqIGFzIElFbnVtZXJhYmxlOwoJCQlmb3JlYWNoICh2YXIgaXRlbSBpbiBhcnJheSkKCQkJCWZvcmVhY2ggKHZhciBzdHIgaW4gX0ZpbmRTdHJpbmdWYWx1ZXMoaXRlbSwgdmlzaXRlZE9iamVjdHMpKQoJCQkJCXlpZWxkIHJldHVybiBzdHI7CiAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgIHlpZWxkIGJyZWFrOwoJCX0KCQkKICAgICAgICBpZiAodHlwZS5Jc0NsYXNzKQoJCXsKCQkJRmllbGRJbmZvW10gZmllbGRzID0gdHlwZS5HZXRGaWVsZHMoQmluZGluZ0ZsYWdzLlB1YmxpYyB8IEJpbmRpbmdGbGFncy5Ob25QdWJsaWMgfCBCaW5kaW5nRmxhZ3MuSW5zdGFuY2UpOwoJCQlmb3JlYWNoIChGaWVsZEluZm8gZmllbGQgaW4gZmllbGRzKQoJCQl7CgkJCQlvYmplY3QgaXRlbSA9IGZpZWxkLkdldFZhbHVlKG9iaik7CgkJCQkKICAgICAgICAgICAgICAgIGlmIChpdGVtID09IG51bGwpCgkJCQkJY29udGludWU7CiAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgCgkJCQlmb3JlYWNoICh2YXIgc3RyIGluIF9GaW5kU3RyaW5nVmFsdWVzKGl0ZW0sIHZpc2l0ZWRPYmplY3RzKSkKCQkJCQl5aWVsZCByZXR1cm4gc3RyOwoJCQl9CiAgICAgICAgICAgIAogICAgICAgICAgICB5aWVsZCBicmVhazsKCQl9ICAgIAkKICAgIH0KfQ==