私は現在dynamic-linqを使用しているコードに取り組んでいますが、リストに実際にPerson
クラスのリストが含まれているList<BaseClass>
を使用すると問題が発生しました。
次のコードを実行すると、 ParseException
ます。
var list = new List<BaseClass>();
list.Add(new Person
{
FirstName = "Joe",
Surname = "Bloggs"
});
list.Where("FirstName == @0", "Joe");
そして例外:
以下のBaseClass
参照してください。
public class BaseClass
{
public int Id { get; set; }
}
そしてPerson
クラス:
public class Person : BaseClass
{
public string FirstName { get; set; }
public string Surname { get; set; }
}
次のコードを実装することでエラーを克服できます。
var list = new List<BaseClass>();
list.Add(new Person
{
FirstName = "Joe",
Surname = "Bloggs"
});
var newList = CreateListOfCorrectType<BaseClass>(list);
newList.Where("FirstName == @0", "Joe");
以下のCreateListOfCorrectType<T>
メソッドを参照してください。
private IList CreateListOfCorrectType<T>(
List<T> list)
{
if (list.Count == 0)
{
return list;
}
var typeInfo = list.FirstOrDefault().GetType();
var correctListType = typeof(List<>).MakeGenericType(typeInfo.UnderlyingSystemType);
var listOfCorrectType = (Activator.CreateInstance(correctListType)) as IList;
list.ForEach(x => listOfCorrectType.Add(x));
return listOfCorrectType;
}
私の質問は、 CreateListOfCorrectType
を使用することが問題を克服する最良の方法かどうかです。そうでない場合、 List<BaseClass>
を正しいタイプに取得するためにどのような選択肢がありますか。
これを既存のコードで使用したいと考えています。既存のList<>
タイプを変更することはできません。また、 CreateListOfCorrectType
メソッドはPerson
クラスを認識しません。
クラス名と変数は説明のみを目的としています。
更新
以下のOptimistの答えは私を私の問題の解決に導きました、以下で使用される拡張メソッドを参照してください:
public static IList ToDerivedListType(this IList list)
{
if (list == null || list.Count == 0)
{
return list;
}
var type = list.Cast<object>().FirstOrDefault().GetType();
var castedList = typeof(Enumerable).GetMethod("Cast", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)
.MakeGenericMethod(type)
.Invoke(null, new[] { list });
return typeof(Enumerable).GetMethod("ToList", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)
.MakeGenericMethod(type)
.Invoke(null, new[] { castedList }) as IList;
}
System.Linq.Enumerable.Cast
とMakeGenericMethod
がキーでした。
実際のユースケースに応じて、いくつかの点で改善できます。
CreateListOfCorrectType
関数はすべての要素を新しいコレクションにコピーします。これにより、返されたコレクションからサブセットのみが取得された場合に、不要な費用が発生します。 IEnumerable
動作するように拡張できます。 System.Linq.Enumerable.Cast
およびMakeGenericMethod
を使用して、 MakeGenericMethod
ことを実現できます。
static public class Extension
{
static public IEnumerable CastDynamic(this IEnumerable Source, Type Type)
{
return
(IEnumerable)
typeof(Enumerable)
.GetMethod("Cast", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)
.MakeGenericMethod(Type)
.Invoke(null, new[] { Source });
}
static public IEnumerable CastToFirstType(this IEnumerable Source)
{
if (0 == Source.Take(1).Count())
{
return Source;
}
return CastDynamic(Source, Source.Cast<object>().FirstOrDefault().GetType());
}
static public IEnumerable WhereCastToFirstType(this IEnumerable Source, string Predicate, params object[] values)
{
return Source.CastToFirstType().Where(Predicate, values);
}
}
スローされた例外に関して示した機能を模倣しようとした場合。マッピング関数が戻った後にキャストが行われるため、違いがあります。
OfType linqメソッドの使用についてはどうですか。
list.OfType<Person>().Where("FirstName == @0", "Joe");
https://msdn.microsoft.com/en-us/library/vstudio/bb360913(v=vs.100).aspxを参照してください