#entity-framework #linq-to-sql #entity-framework-4.1
#entity-framework #linq-to-sql #entity-framework-4.1
Вопрос:
у меня вопрос.у меня есть метод (фильтр), я хочу передать T динамический. но он не принимает. как я могу это сделать?
public List<T> Filter<T>(string TypeOfCompare)
{
List<T> ReturnList2 = new List<T>();
return ReturnList2;
}
IList MakeListOfType(Type listType)
{
Type listType1 = typeof(List<>);
Type specificListType = listType.MakeGenericType(listType1);
return (IList)Activator.CreateInstance(specificListType);
}
Filter < ConstructGenericList(h) > ("s");
Комментарии:
1. Вы не можете; дженерики проверяются во время компиляции, в этом весь смысл. Это не значит, что нет лучших способов выполнить то, что вам нужно. Вместо того, чтобы предлагать нам предлагаемое решение, которое не имеет смысла, расскажите нам, чего вы пытаетесь достичь на высоком уровне.
Ответ №1:
IList MakeListOfType(Type listType)
{
Type listType1 = typeof(List<>);
Type specificListType = listType.MakeGenericType(listType1);
return (IList)Activator.CreateInstance(specificListType);
}
Должно быть наоборот, вы должны вызывать MakeGenericType
определение универсального типа, а не аргумент универсального типа. Итак, код становится таким:
IList MakeListOfType(Type elementType)
{
Type listType = typeof(List<>);
Type specificListType = listType.MakeGenericType(elementType);
return (IList)Activator.CreateInstance(specificListType);
}
(обратите внимание, что я изменил имена переменных, чтобы сделать код более понятным)
Ответ №2:
Общие параметры должны иметь тип, который можно определить во время компиляции (не прибегая к чему-то вроде вывода функционального типа, который есть в некоторых других языках). Итак, вы не можете просто вставить функцию между угловыми скобками, чтобы получить нужный тип.
Редактировать:
Теперь, когда я знаю, что вы пытаетесь сделать, я бы предложил совершенно другой подход.
Вы упоминаете, что используете Entity Framework, и пытаетесь использовать один метод для получения списка объектов разных типов. Однако эти объекты, такие как Student и Teacher, должны иметь что-то общее, иначе вы бы не пытались использовать один и тот же метод для получения их списка. Например, вы можете просто захотеть отобразить имя и иметь идентификатор для использования в качестве ключа.
В этом случае я бы предложил определить интерфейс, который имеет свойства, общие для Student , Teacher и т. Д., Которые вам действительно нужны, А затем возвращает список этого типа интерфейса. В рамках метода вы, по сути, будете использовать вариант заводского шаблона.
Итак, вы могли бы определить интерфейс, например:
public interface INamedPerson
{
int ID { get; }
string FirstName { get; }
string LastName { get; }
}
Сделайте так, чтобы ваши сущности реализовали этот интерфейс. Автоматически сгенерированные объекты (обычно) являются частичными классами, поэтому в ваших собственных новых файлах кода (не в самих файлах автоматически сгенерированного кода) вы должны сделать что-то вроде:
public partial class Student : INamedPerson
{
public int ID
{
get
{
return StudentId;
}
}
}
и
public partial class Teacher : INamedPerson
{
public int ID
{
get
{
return TeacherId;
}
}
}
Теперь вам может даже не понадобиться добавлять ID
свойство, если оно у вас уже есть. Однако, если свойство identity в каждом классе отличается, этот адаптер может быть одним из способов реализации необходимого вам интерфейса.
Тогда для самого метода примером будет:
public List<INamedPerson> MakeListOfType(Type type)
{
if (type == typeof(Student))
{
// Get your list of students. I'll just use a made-up
// method that returns List<Student>.
return GetStudentList().Select<Student, INamedPerson>(s => (INamedPerson)s)
.ToList<INamedPerson>();
}
if (type == typeof(Teacher))
{
return GetTeacherList().Select<Teacher, INamedPerson>(t => (INamedPerson)t)
.ToList<INamedPerson>();
}
throw new ArgumentException("Invalid type.");
}
Теперь, безусловно, есть способы усовершенствовать этот шаблон. Если у вас много связанных классов, вы можете захотеть использовать какую-то среду внедрения зависимостей. Кроме того, вы можете заметить, что существует много дублирования кода. Вместо этого вы могли бы передать функцию (например GetStudentList
, или GetTeacherList
), выполнив что-то вроде
public List<INamedPerson> GetListFromFunction<T>(Func<IEnumerable<T>> theFunction) where T : INamedPerson
{
return theFunction().Select<T, INamedPerson>(t => (INamedPerson)t).ToList<INamedPerson>();
}
Конечно, использование этой функции требует, опять же, чтобы переданный тип был известен во время компиляции. Однако в какой-то момент вам нужно будет выбрать тип, так что, возможно, это подходящее время. Кроме того, вы можете немного упростить свою жизнь, отказавшись от универсального типа во время вызова метода; пока вы передаете функцию, которая не принимает аргументов и возвращает IEnumerable
объекты того же типа, которые реализуют INamedPerson
, компилятор может выяснить, что использовать для универсального типа T
.
Комментарии:
1. у меня есть флажок, который указывает, что это ученик, учитель, .. что они являются моей сущностью. я хочу, чтобы при выборе пользователем одного из них я получал (например, пользователь выбирал имя ученика) и с помощью метода MakeListOfType составлял список учеников, я хочу передать список в свой метод фильтрации и что-то сделать. как я могу это сделать?