Tôi đã tạo ra một hàm nhận lệnh SQL và tạo ra kết quả đầu ra có thể được sử dụng để điền vào một Danh sách các cá thể lớp. Mã hoạt động rất tốt. Tôi đã bao gồm một phiên bản hơi đơn giản mà không cần xử lý ngoại lệ ở đây chỉ để tham khảo - bỏ qua mã này nếu bạn muốn nhảy ngay vấn đề. Nếu bạn có gợi ý ở đây, mặc dù, tôi là tất cả tai.Làm cách nào để tạo và truy cập một cá thể mới của một Lớp ẩn danh được chuyển như một tham số trong C#?
public List<T> ReturnList<T>() where T : new()
{
List<T> fdList = new List<T>();
myCommand.CommandText = QueryString;
SqlDataReader nwReader = myCommand.ExecuteReader();
Type objectType = typeof (T);
FieldInfo[] typeFields = objectType.GetFields();
while (nwReader.Read())
{
T obj = new T();
foreach (FieldInfo info in typeFields)
{
for (int i = 0; i < nwReader.FieldCount; i++)
{
if (info.Name == nwReader.GetName(i))
{
info.SetValue(obj, nwReader[i]);
break;
}
}
}
fdList.Add(obj);
}
nwReader.Close();
return fdList;
}
Như tôi đã nói, điều này chỉ hoạt động tốt. Tuy nhiên, tôi muốn có thể gọi một hàm tương tự với một lớp vô danh vì lý do hiển nhiên.
Câu hỏi # 1: có vẻ như tôi phải xây dựng một lớp vô danh dụ trong cuộc gọi đến phiên bản ẩn danh của chức năng này - có đúng không? Cuộc gọi mẫu là:
.ReturnList(new { ClientID = 1, FirstName = "", LastName = "", Birthdate = DateTime.Today });
Câu hỏi # 2: phiên bản ẩn danh của hàm Danh sách quay lại của tôi bên dưới. Bất cứ ai có thể cho tôi biết lý do tại sao cuộc gọi đến info.SetValue chỉ đơn giản là không làm gì? Nó không trả về lỗi hoặc bất cứ điều gì nhưng nó cũng không thay đổi giá trị của trường mục tiêu.
public List<T> ReturnList<T>(T sample)
{
List<T> fdList = new List<T>();
myCommand.CommandText = QueryString;
SqlDataReader nwReader = myCommand.ExecuteReader();
// Cannot use FieldInfo[] on the type - it finds no fields.
var properties = TypeDescriptor.GetProperties(sample);
while (nwReader.Read())
{
// No way to create a constructor so this call creates the object without calling a ctor. Could this be a source of the problem?
T obj = (T)FormatterServices.GetUninitializedObject(typeof(T));
foreach (PropertyDescriptor info in properties)
{
for (int i = 0; i < nwReader.FieldCount; i++)
{
if (info.Name == nwReader.GetName(i))
{
// This loop runs fine but there is no change to obj!!
info.SetValue(obj, nwReader[i]);
break;
}
}
}
fdList.Add(obj);
}
nwReader.Close();
return fdList;
}
Bất kỳ ý tưởng nào?
Lưu ý: khi tôi cố gắng sử dụng mảng FieldInfo như tôi đã làm trong hàm ở trên, mảng typeFields có phần tử 0 (mặc dù objectType hiển thị tên trường - lạ). Vì vậy, tôi sử dụng TypeDescriptor.GetProperties thay thế.
Bất kỳ lời khuyên và hướng dẫn nào khác về việc sử dụng các lớp phản chiếu hoặc ẩn danh đều thích hợp ở đây - Tôi tương đối mới với ngôn ngữ C# cụ thể này.
CẬP NHẬT: Tôi phải cảm ơn Jason về chìa khóa để giải quyết vấn đề này. Dưới đây là mã sửa đổi sẽ tạo ra một danh sách các cá thể lớp ẩn danh, điền vào các trường của mỗi cá thể từ một truy vấn.
public List<T> ReturnList<T>(T sample)
{
List<T> fdList = new List<T>();
myCommand.CommandText = QueryString;
SqlDataReader nwReader = myCommand.ExecuteReader();
var properties = TypeDescriptor.GetProperties(sample);
while (nwReader.Read())
{
int objIdx = 0;
object[] objArray = new object[properties.Count];
foreach (PropertyDescriptor info in properties)
objArray[objIdx++] = nwReader[info.Name];
fdList.Add((T)Activator.CreateInstance(sample.GetType(), objArray));
}
nwReader.Close();
return fdList;
}
Lưu ý rằng truy vấn đã được tạo và tham số được khởi tạo trong cuộc gọi trước đó với phương pháp của đối tượng này. Mã ban đầu có một tổ hợp vòng lặp bên trong/bên ngoài để người dùng có thể có các trường trong lớp ẩn danh của họ không khớp với một trường. Tuy nhiên, để đơn giản hóa thiết kế, tôi đã quyết định không cho phép điều này và thay vào đó đã chấp nhận truy cập trường db được Jason đề xuất. Ngoài ra, nhờ Dave Markle cũng giúp tôi hiểu thêm về sự cân bằng trong việc sử dụng Activator.CreateObject() so với GenUninitializedObject.
Jason - cảm ơn bạn! Tôi thực sự đánh giá cao mọi nỗ lực. Tôi đã không làm việc thông qua lời khuyên của bạn được nêu ra nhưng nó là chính xác những gì tôi đang tìm kiếm: đặc biệt là các thông tin về những hạn chế và Activator.CreateInstance. –
Một điều cuối cùng: Tôi coi đơn giản hóa bạn đã cung cấp nhưng tôi chưa quyết định liệu tôi có yêu cầu có trường phù hợp trong truy vấn cho từng trường trong đối tượng không, vì vậy tôi vẫn linh hoạt ngay bây giờ. Cảm ơn, mặc dù, vẫn còn lời khuyên tốt. –
Hmmm ... thực ra, với yêu cầu rằng có một trường trong hàm tạo cho mỗi trường trong đối tượng ban đầu, có áp lực hơn một chút để yêu cầu tất cả các trường đều khớp nhau (vì vậy tôi không phải thiết lập các giá trị giả cho các trường bị thiếu, v.v.). –