変数は、後日定義される変数であることが意図されているように見えます。式をそのように変更可能にしたい場合は、リフレクションを使用するのが最善の策です。
まず、目的のプロパティの PropertyInfo への参照を取得する必要があります。これを行うには、Type.GetProperty(string name)を呼び出します。PropertyInfo への参照を取得したら、PropertyInfo.GetValue(Object obj, Object[] index)を呼び出して、特定のインスタンスの値を取得できます。
指定したプロパティが null でない項目のみを取得する LINQ クエリを作成する例を次に示します。
// Declare this as a Generic method of Type T so that we can pass in a
// List containing anything and easily get the appropriate Type object
public static IEnumerable<T> SelectNonNull<T>(
IEnumerable<T> ListItems, string propertyName)
{
IEnumerable<T> itemsFromList;
// Get a reference to the PropertyInfo for the property
// we're doing a null-check on.
PropertyInfo variable = typeof(T).GetProperty(propertyName);
if (variable == null)
{
// The property does not exist on this item type:
// just return all items
itemsFromList = from item in ListItems
select item;
}
else
{
itemsFromList = from item in ListItems
// GetValue will check the value of item's
// instance of the specified property.
where variable.GetValue(item, null) != null
select item;
}
return itemsFromList;
}
質問の結果を取得するには、次のようにこの関数を使用できます。
var NonNullCountries = SelectNonNull(ListItems, "Countries");
var NonNullCities = SelectNonNull(ListItems, "cities");
別の方法として、これを拡張メソッドとして宣言することもできます (他の Linq メソッドと同様)。
public static IEnumerable<T> SelectNonNull<T>(
this IEnumerable<T> source,
string propertyName)
{
PropertyInfo variable = typeof(T).GetProperty(propertyName);
if (variable == null)
{
// Specified property does not exist on this item type:
//just return all items
return from item in source
select item;
}
else
{
return from item in source
where variable.GetValue(item, null) != null
select item;
}
}
次に、複数の呼び出しを連鎖させることができます。たとえば、「都市」と「国」が null であるすべてのエントリを除外したい場合は、次のように使用できます。
var NonNullCitiesOrCountries = ListItems.SelectNonNull("Countries")
.SelectNonNull("cities");
注: SelectNonNull は IEnuerable を返すだけです。クエリの結果を取得するには、それを列挙する必要があります。