Я думаю, что следующий фрагмент может дать вам то, что вы хотите. По сути, он выполняет итерацию по свойствам типа элемента списка, чтобы получить их имена, а в случае общего типа свойства c рекурсивно получает имена свойств аргументов универсального типа c.
public DataTable CreateTable(List<dynamic> Moments)
{
var table = new DataTable();
var elementType = GetElementType(Moments);
var propertyNames = GetPropertyNames(elementType);
// Do something with the property names . . .
return table;
}
private static Type GetElementType(IEnumerable<dynamic> list) =>
list.GetType().GetGenericArguments()[0];
private static IEnumerable<string> GetPropertyNames(Type t)
{
return t.GetProperties().SelectMany(getPropertyNamesRecursively);
IEnumerable<string> getPropertyNamesRecursively(PropertyInfo p) =>
p.PropertyType.IsGenericType
? p.PropertyType.GetGenericArguments().SelectMany(GetPropertyNames)
: new[] { p.Name };
}
Обратите внимание, что это смотрит только на свойства, а ваши текущие классы используют исключительно поля. Однако использование свойств считается наилучшей практикой для доступа publi c к данным, поэтому, возможно, стоит изменить ваши поля на свойства. Если вы действительно хотите сохранить их как поля, вам, возможно, придется немного подправить его, но идея рекурсивного развертывания типов generi c остается прежней.