从通用数据类型

时间:2018-05-01 20:45:56

标签: c# asp.net linq asp.net-core selectlistitem

我有以下代码返回包含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始终获取“.Name”属性。

我怎样才能使这个通用?我试图实现这样的东西,虽然它在语法上是不正确的,可能是不正确的方法:

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;
}));

2 个答案:

答案 0 :(得分:2)

您可以为通用列表对象创建自定义扩展,然后使用反射检索要映射到SelectListItem.Text和Name字段的值。注意我正在使用&#34; nameof&#34;为了防止我试图映射的属性的任何混淆或魔术字符串表示。

我确实定义了一个默认值&#34; Name&#34;到namePropertyName参数。根据您的描述,按照惯例,大多数您的DTO都拥有属性&#34; Name&#34;在他们中。如果不是这种情况,只需删除已定义的默认值。

可以对此扩展进行其他检查以防止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));

以下是TestDto类供参考:

public class TestDto
{
    public int TestId { get; set; }
    public string Name { get; set; }
}

答案 1 :(得分:0)

一些准备工作

如果可以更改表列名称,则使用约定。例如,始终将&#34; Value&#34;命名为栏&#34; X&#34;和&#34;文字&#34;栏&#34; Y&#34; (给他们更好的名字)。然后使这些表的所有类实现类似于此的接口:

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();