我有以下代码,有关如何解决此问题的任何想法,而不是在函数外声明一个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;
}
答案 0 :(得分:8)
这个功能似乎有很多东西错误。
您有一个递归函数,创建一个新的实体上下文 - 并在处理上下文之前进行递归!因此,这不仅会创建大量冗余的ObjectContext
实例,而且它们都是同时使用。整个事情应该被完全重写,以便在函数调用之间共享一个上下文。
您在静态方法中创建ObjectContext
。这真是糟糕的设计。特别是考虑到这个方法的名称,你可能会滥用静态方法来实现有效的过程代码。这应该是一个实例方法,该类应该是实际维护ObjectContext
的东西。
你有很多这样的行:GetNumberOfDevicesForManagementGroup(managementGroupId, firstTime);
。除了浪费CPU周期和数据库时间之外,它们什么都不做。你丢掉了从他们那里得到的结果。看起来您认为GetNumberOfDevicesForManagementGroup
的连续执行将共享相同的counter
变量;那不是递归的工作原理,那不是子程序的工作原理,而是使counter
成为一个全局变量来补偿错误的错误。
您只需下载所有“设备”并逐个计算,而不是在每个实例中实际获得计数。这又是对CPU和数据库时间的巨大浪费。
您正在循环中运行数据库查询。让人惊讶。
第一个firstTime = false;
块中的两行counter = 0;
和if
根本不执行任何操作。您正在分配函数参数。这些都是无操作。
您实际上从未对counter
块初始化else
,因此编译器错误确实不足为奇。如果你想增加一个变量,比如counter++
,它必须从某个地方开始。
老实说,它看起来像是一些狡猾的程序代码,它已随意“转换”为C#。您需要完全重写此方法。您可能需要重做很多设计。
这是一个重写类的示例,如果我已正确理解您的代码,将完成相同的任务(获取单个管理组和其子树中所有管理组的设备数量):< / p>
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;
}
}
请注意,这仍然不会很好地执行,因为它使用每个子组的新查询来锤击数据库;为了实现这个目的,您需要在数据库本身中实现递归查询。
答案 1 :(得分:4)
您似乎误解了递归函数的工作原理:您没有返回结果(即使在函数末尾还有return
!)。您似乎认为递归调用之间共享counter
- 但情况恰恰相反。事实上,递归的原理是基于 no 共享发生的事实。
每次递归调用都会获得 new counter
变量。将所有这些结果添加到一起是您的职责。例如,只需要递归锚点:
if (firstTime)
{
firstTime = false;
counter = 0;
GetNumberOfDevicesForManagementGroup(managementGroupId, firstTime);
}
这是错的;它应该看起来像这样:
if (firstTime)
{
return GetNumberOfDevicesForManagementGroup(managementGroupId, false);
}
这里重要的是返回结果。但是设置firstTime
是不必要的(并且不常见),并且根本不需要设置counter
。
方法体的其余部分必须相应更改。
(另外,这个递归锚似乎毫无意义。它也可以省略。)
答案 2 :(得分:0)
将
为什么不在函数之外使它静止?counter
初始化为零以使编译器静音!事实上
static int counter = 0; public static int GetNumberOfDevicesForManagementGroup(Guid managementGroupId, bool firstTime) { .... }
编辑:看来OP希望在函数范围内有一个变量,另一种方法是修改函数的签名以包含变量的参数{ {1}}并将其设为counter
参数而不是......
希望这有帮助, 最好的祝福, 汤姆。
答案 3 :(得分:0)
这样写:
您可以将计数器值作为参数插入。
public static int GetNumberOfDevicesForManagementGroup(Guid managementGroupId, bool firstTime, int counterValue)
{
int counter = 0;
counter = counterValue;
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;
}
您可以将计数器值作为参数插入。
答案 4 :(得分:0)
正如其他人所建议的那样,如果您在声明时将counter
初始化为零,则可以解决编译问题。但只有那一个。
但是......为什么使用firstTime
参数作为累加器?为什么不完全删除它并且根本不使用累加器呢?
public static int GetNumberOfDevicesForManagementGroup(Guid managementGroupId)
{
// *** Initialization
int counter = 0;
using (/* ... */)
{
// *** No first time special case
var groups = // ...
if (groups.Count != 0)
{
foreach (ManagementGroups group in groups)
{
// *** No need to call ToList() to count
counter += ctx.Devices
.Count(x => x.ManagementGroups.ManagementGroupId == group.ManagementGroupId)
// *** Add recursive result
counter += GetNumberOfDevicesForManagementGroup(group.ManagementGroupId);
}
}
else
{
// *** Use LINQ to count
counter = devices.Count(x => x.ManagementGroups.ManagementGroupId == group.ManagementGroupId);
}
}
return counter;
}