我已經創建了一個函數,它接受一個SQL命令併產生可用於填充類實例列表的輸出。代碼很好。我已經包含了一個稍微簡化的版本,但沒有異常處理,僅供參考 - 如果您想跳過此問題,請跳過此代碼。如果你在這裏有建議,但我是全部耳朵。如何創建並訪問在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;
}
正如我所說,這工作得很好。不過,我希望能夠通過匿名類別調用類似的功能,原因很明顯。
問題1:看來我必須在我的匿名版本的函數中調用匿名類實例 - 這是正確的嗎?一個示例調用是:
.ReturnList(new { ClientID = 1, FirstName = "", LastName = "", Birthdate = DateTime.Today });
問題2:我的ReturnList函數的匿名版本如下。任何人都可以告訴我爲什麼對info.SetValue的調用根本沒有做什麼?它不會返回錯誤或任何內容,但它也不會更改目標字段的值。
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;
}
任何想法?
Note:當我嘗試使用FieldInfo數組,就像我在上面的函數中那樣,typeFields數組有零個元素(即使objectType顯示字段名稱 - 奇怪)。因此,我改用TypeDescriptor.GetProperties。
任何其他有關使用反射或匿名類的提示和指導都適用於此 - 我對C#語言這個特定的角落相對較新。
更新:我必須感謝傑森解決這個問題的關鍵。下面是修改後的代碼,它將創建一個匿名類實例列表,填充查詢中每個實例的字段。
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;
}
請注意,查詢已構造並且參數已在以前調用此對象的方法時初始化。原始代碼有一個內部/外部循環組合,以便用戶可以在其匿名類中的字段與字段不匹配。然而,爲了簡化設計,我決定不允許這樣做,而是採用Jason推薦的db字段訪問方式。此外,感謝Dave Markle以及幫助我更好地瞭解使用Activator.CreateObject()與GenUninitializedObject進行權衡。
傑森 - 謝謝!我非常感謝所有的努力。我還沒有通過你的建議,但它正是我所期待的:特別是關於限制和Activator.CreateInstance的信息。 – 2009-01-25 23:25:35