从通用数据类型填充 SelectListItem
Populate SelectListItem from generic data type
我有以下代码,returns 来自数据库 table,包含一个 Id 字段和一个 Name 字段,并将其传输到 SelectListItems 列表(这会填充一个下拉框我的观点。)
var locationTypes = await APIHelper.GetAsync<List<LocationType>>(url);
var items = new List<SelectListItem>();
items.AddRange(locationTypes.Select(locationType =>
{
var item = new SelectListItem();
item.Value = locationType.LocationTypeId.ToString();
item.Text = locationType.Name;
return item;
}));
我在整个应用程序中多次重复这一点,将 LocationType 替换为其他各种内容。 item.Value总是获取返回数据的Id属性(Id字段总是{TableName}+"Id"的格式),item.Text总是获取" .名称" 属性.
我怎样才能使它通用?我正在尝试实现这样的目标,尽管它在语法上不正确并且可能是不正确的方法:
var myGenericObjects = await APIHelper.GetAsync<List<T>>(url)
var items = new List<SelectListItem>();
items.AddRange(myGenericObjects .Select(myGenericObjects =>
{
var item = new SelectListItem();
item.Value = myGenericObject.Field[0].ToString();
item.Text = myGenericObject.Name;
return item;
}));
您可以为通用列表对象创建自定义扩展,然后使用反射检索要映射到 SelectListItem.Text 和名称字段的值。请注意,我使用 "nameof" 是为了防止我试图映射到的属性的任何混淆或魔术字符串表示。
我确实为 namePropertyName 参数定义了默认值 "Name"。根据您的描述,按照惯例,您的大多数 DTO 中都有 属性 "Name"。如果不是这种情况,只需删除定义的默认值。
可以对此扩展进行额外的检查以防止 NullReference 和 ArgumentExceptions,但为了示例的简单性被省略了。示例:确保在 idPropertyName 和 namePropertyName 参数中提供了一个值,并确保这些 属性 名称在转换之前存在于所提供的通用对象上。
public static class ListExtensions
{
public static List<SelectListItem> ToSelectList<T>(this List<T> list, string idPropertyName, string namePropertyName = "Name")
where T : class, new()
{
List<SelectListItem> selectListItems = new List<SelectListItem>();
list.ForEach(item =>
{
selectListItems.Add(new SelectListItem
{
Text = item.GetType().GetProperty(namePropertyName).GetValue(item).ToString(),
Value = item.GetType().GetProperty(idPropertyName).GetValue(item).ToString()
});
});
return selectListItems;
}
}
使用示例:
var testList = new List<TestDto>
{
new TestDto { Name = "Test0", TestId = 0 },
new TestDto { Name = "Test1", TestId = 1 },
new TestDto { Name = "Test2", TestId = 2 },
new TestDto { Name = "Test3", TestId = 3 },
new TestDto { Name = "Test4", TestId = 4 },
};
var selectList = testList.ToSelectList(nameof(TestDto.TestId), nameof(TestDto.Name));
这里是TestDtoclass供参考:
public class TestDto
{
public int TestId { get; set; }
public string Name { get; set; }
}
一些准备工作
如果可以更改 table 列名称,则使用约定。例如,始终将 "Value" 列命名为 "X",将 "Text" 列命名为 "Y"(给它们起更好的名字)。然后让那些 table 的所有 类 实现一个类似这样的接口:
public interface ICustomLookup
{
string X { get; set; }
string Y { get; set; }
}
public class SomeClass : ICustomLookup
{
public string X { get; set; }
public string Y { get; set; }
}
然后像这样的扩展方法:
public static class EnumerableExtension
{
public static SelectList ToSelectList(this IEnumerable<ICustomLookup> items)
{
return new SelectList(items.Select(thisItem => new SelectListItem
{
Text = thisItem.X,
Value = thisItem.Y
}));
}
}
用法
var items = new List<SomeClass>
{
new SomeClass { X = "XOne", Y = "YOne" },
new SomeClass { X = "XTwo", Y = "YTwo" }
};
SelectList selectList = items.ToSelectList();
我有以下代码,returns 来自数据库 table,包含一个 Id 字段和一个 Name 字段,并将其传输到 SelectListItems 列表(这会填充一个下拉框我的观点。)
var locationTypes = await APIHelper.GetAsync<List<LocationType>>(url);
var items = new List<SelectListItem>();
items.AddRange(locationTypes.Select(locationType =>
{
var item = new SelectListItem();
item.Value = locationType.LocationTypeId.ToString();
item.Text = locationType.Name;
return item;
}));
我在整个应用程序中多次重复这一点,将 LocationType 替换为其他各种内容。 item.Value总是获取返回数据的Id属性(Id字段总是{TableName}+"Id"的格式),item.Text总是获取" .名称" 属性.
我怎样才能使它通用?我正在尝试实现这样的目标,尽管它在语法上不正确并且可能是不正确的方法:
var myGenericObjects = await APIHelper.GetAsync<List<T>>(url)
var items = new List<SelectListItem>();
items.AddRange(myGenericObjects .Select(myGenericObjects =>
{
var item = new SelectListItem();
item.Value = myGenericObject.Field[0].ToString();
item.Text = myGenericObject.Name;
return item;
}));
您可以为通用列表对象创建自定义扩展,然后使用反射检索要映射到 SelectListItem.Text 和名称字段的值。请注意,我使用 "nameof" 是为了防止我试图映射到的属性的任何混淆或魔术字符串表示。
我确实为 namePropertyName 参数定义了默认值 "Name"。根据您的描述,按照惯例,您的大多数 DTO 中都有 属性 "Name"。如果不是这种情况,只需删除定义的默认值。
可以对此扩展进行额外的检查以防止 NullReference 和 ArgumentExceptions,但为了示例的简单性被省略了。示例:确保在 idPropertyName 和 namePropertyName 参数中提供了一个值,并确保这些 属性 名称在转换之前存在于所提供的通用对象上。
public static class ListExtensions
{
public static List<SelectListItem> ToSelectList<T>(this List<T> list, string idPropertyName, string namePropertyName = "Name")
where T : class, new()
{
List<SelectListItem> selectListItems = new List<SelectListItem>();
list.ForEach(item =>
{
selectListItems.Add(new SelectListItem
{
Text = item.GetType().GetProperty(namePropertyName).GetValue(item).ToString(),
Value = item.GetType().GetProperty(idPropertyName).GetValue(item).ToString()
});
});
return selectListItems;
}
}
使用示例:
var testList = new List<TestDto>
{
new TestDto { Name = "Test0", TestId = 0 },
new TestDto { Name = "Test1", TestId = 1 },
new TestDto { Name = "Test2", TestId = 2 },
new TestDto { Name = "Test3", TestId = 3 },
new TestDto { Name = "Test4", TestId = 4 },
};
var selectList = testList.ToSelectList(nameof(TestDto.TestId), nameof(TestDto.Name));
这里是TestDtoclass供参考:
public class TestDto
{
public int TestId { get; set; }
public string Name { get; set; }
}
一些准备工作
如果可以更改 table 列名称,则使用约定。例如,始终将 "Value" 列命名为 "X",将 "Text" 列命名为 "Y"(给它们起更好的名字)。然后让那些 table 的所有 类 实现一个类似这样的接口:
public interface ICustomLookup
{
string X { get; set; }
string Y { get; set; }
}
public class SomeClass : ICustomLookup
{
public string X { get; set; }
public string Y { get; set; }
}
然后像这样的扩展方法:
public static class EnumerableExtension
{
public static SelectList ToSelectList(this IEnumerable<ICustomLookup> items)
{
return new SelectList(items.Select(thisItem => new SelectListItem
{
Text = thisItem.X,
Value = thisItem.Y
}));
}
}
用法
var items = new List<SomeClass>
{
new SomeClass { X = "XOne", Y = "YOne" },
new SomeClass { X = "XTwo", Y = "YTwo" }
};
SelectList selectList = items.ToSelectList();