重构一个方法

时间:2017-08-02 17:23:32

标签: c# performance optimization

VS Performance Profiler已将以下方法识别为“热门”。我确信有一个很好的方法可以重构它以使它不那么热,所以只是想知道是否有人有任何建议。

public class CrmWebApiClient
{
    private HttpClient _httpClient;

    public CrmWebApiClient()
    {
        _httpClient = new HttpClient();
        _httpClient.BaseAddress = new Uri("https://crmbaseaddress.com");            
    }

    internal async Task Initialize()
    {
        try
        {               
            var authority = "https://adfsServerUrl/adfs/";
            var authContext = new AuthenticationContext(authority,false);
            var credentials = new ClientCredential(clientID,clientSecret);

            var authResult = await authContext.AcquireTokenAsync("https://crmbaseaddress.com", credentials);

            _httpClient.DefaultRequestHeaders.Authorization =
                new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
        }
        catch (Exception ex)
        {
            var error = ex;
        }

    }

    internal async Task<string> GetValuesAsync()
    {
        var result = string.Empty;
        try
        {
            result = await _httpClient.GetStringAsync("api/data/v8.1/accounts");
        }
        catch (Exception ex)
        {
            var error = ex;
        }

        return result;
    }
}

5 个答案:

答案 0 :(得分:2)

您正在循环数据两次,并且您从数据库中提取的数据超出了您真正需要的数量。

public static IEnumerable<SelectListItem> GetJurisdictions()
{
    using (var context = new DAL.ObservationEntities())
    {
        var query = from j in context.Jurisdictions 
                    orderby j.Name
                    select new SelectListItem {
                        Text = item.Name,
                        Value = item.GUID.ToString(),
                    };
        return query.ToList();
    }
}

您的原始代码基本上正在执行SELECT * FROM Jurisdictions ORDER BY Name,然后将数据循环两次。

答案 1 :(得分:1)

最大的问题是你这里没有where条款,所以你选择整个表格。如果桌子很小,那很好,否则你可能会想要那个。

public static IEnumerable<SelectListItem> GetJurisdictions()
{
    using (var context = new DAL.ObservationEntities())
    {
        var items = (from j in context.Jurisdictions orderby j.Name select new { j.Name, j.GUID })
                    .AsEnumerable()
                    .Select(j => new SelectListItem { Text = j.Name, Value = j.GUID.ToString() })
                    .ToList();

        return items;
    }
}

您可能不需要AsEnumerable()

答案 2 :(得分:1)

好的,有几件不同的事情。

首先,这个功能实际上做了三件事:

  1. 从DAL获取数据
  2. 创建SelectedListItem列表
  3. 它在步骤#1中转换数据并将其放入 在步骤#2中列出。
  4. 为什么这很重要?

    好吧,让我们说你稍后写了一个函数,可以真正使用那个管辖数据。您无法真正重复使用当前功能,因为它不会返回管辖数据 - 它会为您的组合框返回GUI元素。

    或者假设您要缓存数据。您想缓存GUI元素......还是LINQ语句的返回?程序的其他元素可能需要该管辖区数据的不同部分,而不仅仅是名称/ GUID。

    接下来 - 查看当前函数返回的内容:IEnumerable。这意味着它实际上并不是一个完全充实的列表。我的意思是,我应该能够编写这样的代码:

    IEnumerable<int> idList = GetIDEnumerable();
    int firstID = idList.FirstOrDefault();
    

    ......并没有让它实际遍历整个数据集。 GetIDEnumerable()可能包含1000万行...但如果我做得对,那么除了第一行之外,该过程不必触及任何内容!但是,在您声明列表并填充它们的那一刻,您就必须遍历所有记录。 (现在可能没关系,但想象一下你以后需要写一个函数来获得符合某个标准的第一个管辖区 - 你现在不能快速做到这一点,因为你的函数遍历所有记录。)< / p>

    所以,我在这里改变它:

    首先,创建你的IEnumerable GetJurisdictionEnumerable()函数,它所做的只是返回LINQ语句,如:

    IEnumerable<???> GetJursidctionEnumerableFromDB()
    {
        using (var context = new DAL.ObservationEntities())
            return (from j in context.Jurisdictions orderby j.Name select j);
        }
    }
    

    接下来,编写一个函数,从缓存或新结果中收集Jurisdiction项目列表。

    IEnumerable<???> GetJurisdictionEnumerable()
    {
        if (cached data is still good)
            return a cached List<???> object.
        // we don't want the cache to be IEnumerable - we want to actually store the contents,
        // not just a way of enumerating through the contents
        cached List<???> = GetJurisdictionEnumerableFromDB().ToList();
        return cached List<???>
    }
    

    之后,将一个将Jurisdiction元素转换为GUI项的函数:

    SelectedListItem TransformJurisdictionIntoComboElement(??? jurisRecord)
    {
        return new SelectedListItem()
        {
            Text = jurisRecord.Name.ToString(),
            Value = jurisRecord.GUID.ToString()
        }
    }
    

    最后,当你想填充组合框

    // ... code to populate combo box
    IEnumerable<???> jurisData = GetJurisdictionEnumerable();
    foreach(??? j in jurisData)
        combobox.Add(TransformJurisdictionIntoComboElement(j));
    

    它的3个功能而不是1个(好吧,它只有2个没有缓存),但它并没有违反SRP。如果您的代码将来发生变化,它会更加灵活。

答案 3 :(得分:0)

我可以看到一个便宜的优化:您的items对象不需要变成List,因为它可以作为普通IEnumerable进行迭代。

更新的代码:

public static IEnumerable<SelectListItem> GetJurisdictions()
{
    using (var context = new DAL.ObservationEntities())
    {
        List<SelectListItem> JurisdictionsList = new List<SelectListItem>();
        var items = (from j in context.Jurisdictions orderby j.Name select j); // Removed toList()
        foreach (var item in items)
        {
            JurisdictionsList.Add(new SelectListItem() { Text = item.Name.ToString(), Value = item.GUID.ToString() });
        }
        return JurisdictionsList;
    }
}

答案 4 :(得分:0)

您可以只选择Jurisdictions名称而不是整个对象。

然而,数据库最有可能需要一段时间才能返回信息。您可以查看缓存结果,而不是在需要此下拉列表时转到数据库。或者您可以查看数据库优化以更快地返回此数据。

哦,您也可以查看已编译的linq查询。第一次构建查询可能需要很长时间。