I couldn't stop playing with this little toy. Thank you, Andrey!
Attached you will a version based most faithfully on yours, demonstrating
1) attributes with non-unique tags,
2) property transfer via Reflection, and
3) Keywords to allow selection of boolean command options.
One additional minor change in an area where the original ATTSYNC may fail too is checking for erased ObjectIds when collecting the definitions.
Using KeyValuePair as a poor man's Tuple, I tried to harness the full power of Linq's Join() method:
// Extension for set intersection based on unique keys
static IEnumerable<KeyValuePair<S, T>> IntersectByKey<S, T>(this IEnumerable<KVP<S>> s, IEnumerable<KVP<T>> other)
{
return s.Join(other, x => x.Key, x => x.Key, (x, y) => new KeyValuePair<S, T>(x.Value, y.Value));
}
// Extension for set difference based on unique keys
static IEnumerable<S> DifferenceByKey<S, T>(this IEnumerable<KVP<S>> s, IEnumerable<KVP<T>> other)
{
return s.Where(ik => !other.Any(jk => jk.Key.Equals(ik.Key))).Select(ik => ik.Value);
}
...
}
struct KVP<T>
{
public KeyValuePair<int, string> Key;
public T Value;
}
Zip is attached.