递归函数内的局部变量未分配

fAR*_*cRY 1 c# recursion

我有以下代码,有关如何解决此问题的任何想法,而不是在函数外声明一个int变量?我得到以下编译器错误:使用未分配的局部变量'counter'

public static int GetNumberOfDevicesForManagementGroup(Guid managementGroupId, bool firstTime)
  {
     int counter;
     using (var ctx = new DeviceManagerEntities())
     {
        if (firstTime)
        {
           firstTime = false;
           counter = 0;
           GetNumberOfDevicesForManagementGroup(managementGroupId, firstTime);
        }
        else
        {
           var groups = ctx.ManagementGroups
              .Where(x => x.ParentId == managementGroupId)
              .ToList();
           if (groups.Count != 0)
           {
              foreach (ManagementGroups group in groups)
              {
                 var devices = ctx.Devices
                    .Where(x => x.ManagementGroups.ManagementGroupId == group.ManagementGroupId)
                    .ToList();
                 foreach (Devices device in devices)
                 {
                    counter++;
                 }
                 GetNumberOfDevicesForManagementGroup(group.ManagementGroupId, firstTime);
              }
           }
           else
           {
              var devices = ctx.Devices
                    .Where(x => x.ManagementGroups.ManagementGroupId == managementGroupId)
                    .ToList();
              foreach (Devices device in devices)
              {
                 counter++;
              }
           }
        }
     }
     return counter;
  }
Run Code Online (Sandbox Code Playgroud)

Aar*_*ght 8

这个功能似乎有很多问题.

  1. 您有一个递归函数,可以创建一个新的实体上下文 - 并在处理上下文之前进行递归!因此,这不仅会产生大量冗余ObjectContext实例,而且它们都会同时使用.整个事情应该完全重写,以跨函数调用共享上下文.

  2. ObjectContext静态方法中创建.这真是糟糕的设计.特别是考虑到这个方法的名称,你可能会滥用静态方法来实现有效的过程代码.这应该是一个实例方法,而类应该是实际维护的东西ObjectContext.

  3. 你有很多这样的行:GetNumberOfDevicesForManagementGroup(managementGroupId, firstTime);.除了浪费CPU周期和数据库时间之外,它们什么都不做.你丢掉了从他们那里得到的结果.看起来您认为连续执行GetNumberOfDevicesForManagementGroup将共享相同的counter变量; 这不是递归如何工作,这不是子程序如何工作,并使counter一个全局变量来补偿是错误的错误.

  4. 您只需下载所有"设备"并逐个计算,而不是在每个实例中实际计数.这又是CPU和数据库时间的巨大浪费.

  5. 您正在循环中运行数据库查询.让人惊讶.

  6. 这两行firstTime = false;counter = 0;第一个if块根本不做任何事情.您正在分配函数参数.这些都是无操作.

  7. 你从来没有真正counterelse块做初始化,所以编译错误确实不足为奇.如果你想增加一个变量,比如counter++,它必须从某个地方开始.

老实说,它看起来像是一些狡猾的程序代码,它已被随意"转换"为C#.您需要完全重写此方法.您可能需要重做很多设计.


下面是一个重写类的示例,如果我已正确理解您的代码,将完成相同的任务(获取单个管理组和其子树中所有管理组的设备数):

public class DeviceRepository
{
    private DeviceManagerEntities context;

    public DeviceRepository(DeviceManagerEntities context)
    {
        if (context == null)
            throw new ArgumentNullException("context");
        this.context = context;
    }

    public int GetDeviceCount(Guid managementGroupID)
    {
        return GetDeviceCount(new Guid[] { managementGroupID });
    }

    public int GetDeviceCount(IEnumerable<Guid> managementGroupIDs)
    {
        int deviceCount = context.Devices
            .Where(d => managementGroupIDs.Contains(
                d.ManagementGroups.ManagementGroupID))
            .Count();
        var childGroupIDs = context.ManagementGroups
            .Where(g => managementGroupIDs.Contains(g.ParentId))
            .Select(g => g.ManagementGroupID);
        deviceCount += GetDeviceCount(childGroupIDs);
        return deviceCount;
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这仍然不会很好地执行,因为它使用每个子组的新查询来锤击数据库; 为了实现这个目的,您需要在数据库本身中实现递归查询.