为什么我不能在匿名方法中声明与变量同名的变量

时间:2015-05-19 06:47:22

标签: c# c#-4.0

我正在创建一个方法来将默认用户加载到MVC5模板附带的身份数据库中。我最终遇到了编译错误(参见下面的完整代码)

var user = CreateUser("email@email.email",true);

确切错误为Error 16 A local variable named 'user' cannot be declared in this scope because it would give a different meaning to 'user', which is already used in a 'child' scope to denote something else

我不明白这是怎么回事,我发现同样令人费解的是,当我注释掉这一行时,下一行找不到变量user。如果编译因前一个声明而拒绝让我使用user,那么在删除重复声明后如何找不到user

我认为这与持有名称的闭包/内联方法有关,但我不确定。我也知道我可以通过更改变量名来解决这个问题,我对它的原因更感兴趣。

以下是我目前正在编写的方法的简化示例:

    internal static void CreateDefaultUsers(IdentityDb context)
{
    var defaultPassword = "admin";
    var userManager = new UserManager<User>(new UserStore<User>(context));
    var roleManager = new RoleManager<UserRole>(new RoleStore<UserRole>(context));

    Func<string, User> CreateUser = (string email) =>
    {
        User user = context.Users.SingleOrDefault(u => u.UserName == email);

        if (user == null)
        {
            user = new EziOrderUser { 
            FirstName = email.Substring(0, email.LastIndexOf("@")),
            Email = email, UserName = email, EmailConfirmed = true };

            userManager.Create(user, defaultPassword);

            userManager.AddToRole(user.Id, "User");
        }

        return user;
    };

    var user = CreateUser("email@email.email"); // <-- Error here
    userManager.AddToRole(user.Id, "Administrator"); // <-- Then here
}

(没有检查过这个样本编译,但确实说明了问题)

1 个答案:

答案 0 :(得分:1)

基本上它是一项让您的生活更轻松的功能。 :-)如果你能做到这一点,你可以得到类型冲突。

? f(x) = { (t) -> x + t }
%1 = (x)->(t)->x+t
? g(x) = { local(y); y = f(x); (t) -> y(t) }
%2 = (x)->local(y);y=f(x);(t)->y(t)
? h = g(2)
%3 = (t)->my(x=2);y(t)
? h(1)
  ***   at top-level: h(1)
  ***                 ^----
  ***   in function h: y(t)
  ***                  ^----
  ***   not a function in function call
  ***   Break loop: type 'break' to go back to GP

在您的示例中,** 2和** 1的用户类型是什么?假设CreateUser返回一个字符串 - 这将推断在范围1中用户可以同时获得类型{ // scope 1 Func<string, User> CreateUser = (string email) => { // scope 2 User user = context.Users.SingleOrDefault(u => u.UserName == email); // ...**1 return user; }; // **2 var user = CreateUser("email@email.email"); userManager.AddToRole(user.Id, "Administrator"); // <-- Then here 和类型string。由于范围2已关闭,您可以认为这是正确使用的,但这将使开发人员更难以阅读代码。强制每个范围只能使用一次名称,这样可以更容易。

并非所有语言都有这种行为,f.ex。 C ++允许你做这些事情。 (这可能是他们首先做到这一点的原因: - )

顺便说一句,重新使用名称是可以的,只要它们不会出现在同一范围内。例如:

User