Assuming you have such a class and want to check all the rw public string properties:
using System.Linq;
using System.Reflection;
class Account
{
public string Name { get; set; }
public string Nationality { get; set; }
public string Phone { get; set; }
public int Value { get; set; }
}
We can refactor using reflexion and Linq like that:
var account = new Account();
account.Name = "Name";
var type = account.GetType();
var flags = BindingFlags.Public
| BindingFlags.Instance
| BindingFlags.GetProperty
| BindingFlags.SetProperty;
var property = type.GetProperties(flags)
.Where(p => p.PropertyType == typeof(string))
.Where(p => string.IsNullOrEmpty((string)p.GetValue(account)))
.Select(p => p.Name)
.FirstOrDefault();
if ( property != null )
return BadRequest($"{property} is required");
We take all properties of the type being public instance and not static as well as having getter and setter, then we filter on the required string type and we check the value to select the name of the first found else the result is null.
To not check all string properties, we can use an custom Ignore
attribute:
class IgnoreAttribute : Attribute
{
}
class Account
{
[Ignore]
public string MyString { get; set; }
public string Name { get; set; }
public string Nationality { get; set; }
public string Phone { get; set; }
public int Value { get; set; }
}
The Linq query is now:
var property = type.GetProperties(flags)
.Where(p => p.PropertyType == typeof(string))
.Where(p => p.GetCustomAttribute(typeof(IgnoreAttribute)) == null)
.Where(p => string.IsNullOrEmpty((string)p.GetValue(account)))
.Select(p => p.Name)
.FirstOrDefault();
Also as @Charles mentionned, RequiredAttribute
can be used instead:
using System.ComponentModel.DataAnnotations;
class Account
{
public string MyString { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Nationality { get; set; }
[Required]
public string Phone { get; set; }
public int Value { get; set; }
}
var property = type.GetProperties(flags)
.Where(p => p.PropertyType == typeof(string))
.Where(p => p.GetCustomAttribute(typeof(RequiredAttribute)) != null)
.Where(p => string.IsNullOrEmpty((string)p.GetValue(account)))
.Select(p => p.Name)
.FirstOrDefault();
Or in fact here a NotNullOrEmpty
attribute will be appropriate:
class NotNullOrEmptyAttribute : Attribute
{
}
class Account
{
public string MyString { get; set; }
[NotNullOrEmpty]
public string Name { get; set; }
[NotNullOrEmpty]
public string Nationality { get; set; }
[NotNullOrEmpty]
public string Phone { get; set; }
public int Value { get; set; }
}
var property = type.GetProperties(flags)
.Where(p => p.PropertyType == typeof(string))
.Where(p => p.GetCustomAttribute(typeof(NotNullOrEmptyAttribute)) != null)
.Where(p => string.IsNullOrEmpty((string)p.GetValue(account)))
.Select(p => p.Name)
.FirstOrDefault();
LINQ: One "where" clause versus multiple chained "where clauses"
Proper Linq where clauses
RequiredAttribute Class
How Can I Use Data Annotations Attribute Classes to Fail Empty Strings in Forms?
Creating a Domain Object Validation Framework