для массивов с такими отверстиями [,2,,4,,6,7,,]
, потому что моя проблема заключалась в заполнении этих отверстий. Поэтому я изменил его в соответствии с моей потребностью:)
для меня работало следующее модифицированное решение:)
var arr = [,2,,4,,6,7,,]; //example
while(arr.length < 9){
var randomnumber=Math.floor(Math.random()*9+1);
var found=false;
for(var i=0;i<arr.length;i++){
if(arr[i]==randomnumber){found=true;break;}
}
if(!found)
for(k=0;k<9;k++)
{if(!arr[k]) //if it's empty !!MODIFICATION
{arr[k]=randomnumber; break;}}
}
alert(arr); //outputs on the screen
Вам действительно нужен список, или IEnumerable будет достаточно хорош?
Я знаю, что вы хотите, чтобы он был общим, но гораздо более распространенным шаблоном является использование статического метода Factory на тип целевого объекта, который принимает строку данных (или IDataRecord). Это будет выглядеть примерно так:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public static Employee Create(IDataRecord record)
{
return new Employee
{
Id = record["id"],
Name = record["name"]
};
}
}
.
public IEnumerable<Employee> GetEmployees()
{
using (var reader = YourLibraryFunction())
{
while (reader.Read())
{
yield return Employee.Create(reader);
}
}
}
Тогда, если вам действительно нужен список, а не IEnumerable, вы можете вызвать .ToList ()
по результатам. Я полагаю, вы могли бы также использовать дженерики + делегат, чтобы сделать код этого шаблона более пригодным для повторного использования.
Обновление: Я снова увидел это сегодня, и мне захотелось написать общий код:
public IEnumerable<T> GetData<T>(IDataReader reader, Func<IDataRecord, T> BuildObject)
{
try
{
while (reader.Read())
{
yield return BuildObject(reader);
}
}
finally
{
reader.Dispose();
}
}
//call it like this:
var result = GetData(YourLibraryFunction(), Employee.Create);
Как Волшебство
я лично ОЧЕНЬ НЕ ХОЧУ делать ручное отображение в конструкторах, я - также не поклонник выполнения моего собственного отражения. Таким образом, вот другая любезность решения замечательного (и довольно повсеместна) lib Newtonsoft JSON.
Это будет только работать, если Ваши имена свойства точно будут соответствовать datareader именам столбцов, но это работало хорошо на нас.
... предполагает, что у Вас есть имя datareader "yourDataReader"...
var dt = new DataTable();
dt.Load(yourDataReader);
// creates a json array of objects
string json = Newtonsoft.Json.JsonConvert.SerializeObject(dt);
// this is what you're looking for right??
List<YourEntityType> list =
Newtonsoft.Json.JsonConvert
.DeserializeObject<List<YourEntityType>>(json);
Хотя я бы не рекомендовал это для производственного кода, но вы можете сделать это автоматически, используя отражение и универсальные типы:
public static class DataRecordHelper
{
public static void CreateRecord<T>(IDataRecord record, T myClass)
{
PropertyInfo[] propertyInfos = typeof(T).GetProperties();
for (int i = 0; i < record.FieldCount; i++)
{
foreach (PropertyInfo propertyInfo in propertyInfos)
{
if (propertyInfo.Name == record.GetName(i))
{
propertyInfo.SetValue(myClass, Convert.ChangeType(record.GetValue(i), record.GetFieldType(i)), null);
break;
}
}
}
}
}
public class Employee
{
public int Id { get; set; }
public string LastName { get; set; }
public DateTime? BirthDate { get; set; }
public static IDataReader GetEmployeesReader()
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString);
conn.Open();
using (SqlCommand cmd = new SqlCommand("SELECT EmployeeID As Id, LastName, BirthDate FROM Employees"))
{
cmd.Connection = conn;
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
}
public static IEnumerable GetEmployees()
{
IDataReader rdr = GetEmployeesReader();
while (rdr.Read())
{
Employee emp = new Employee();
DataRecordHelper.CreateRecord<Employee>(rdr, emp);
yield return emp;
}
}
}
Затем вы можете использовать CreateRecord
для создания экземпляра любого класса из полей в средстве чтения данных.
<asp:GridView ID="GvEmps" runat="server" AutoGenerateColumns="true"></asp:GridView>
GvEmps.DataSource = Employee.GetEmployees();
GvEmps.DataBind();
Вы можете создать метод расширения, например:
public static List<T> ReadList<T>(this IDataReader reader,
Func<IDataRecord, T> generator) {
var list = new List<T>();
while (reader.Read())
list.Add(generator(reader));
return list;
}
, и использовать его примерно так:
var employeeList = reader.ReadList(x => new Employee {
Name = x.GetString(0),
Age = x.GetInt32(1)
});
Предложение Джоэла хорошее. Вы можете вернуть IEnumerable
. Приведенный выше код легко преобразовать:
public static IEnumerable<T> GetEnumerator<T>(this IDataReader reader,
Func<IDataRecord, T> generator) {
while (reader.Read())
yield return generator(reader);
}
Если вы хотите автоматически сопоставить столбцы со свойствами, идея кода такая же. Вы можете просто заменить функцию generator
в приведенном выше коде на функцию, которая опрашивает typeof (T)
и устанавливает свойства объекта, используя отражение, считывая совпадающий столбец. Однако я лично предпочитаю определять фабричный метод (например, тот, который упоминается в ответе Джоэла) и передавать его делегат в эту функцию:
var list = dataReader.GetEnumerator(Employee.Create).ToList();