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

Why can I not declare a variable with the same name as a variable in an anonymous method

我正在创建一种方法,将默认用户加载到 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

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

这是我目前正在编写的方法的一个简化示例:

    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
}

(没有检查这个示例编译,但是它确实说明了问题)

基本上,这是一项旨在让您的生活更轻松的功能。 :-) 如果你能做到这一点,你就会遇到类型冲突。

{
// 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

在您的示例中,**2 和 **1 的用户类型是什么?假设 CreateUser returns 是一个字符串 - 这将推断在范围 1 中用户可以获得类型 string 和类型 User。由于范围 2 已关闭,您可以争辩说这是正确使用的范围,但这将使开发人员更难阅读代码。强制每个范围只能使用一个名称会使它更容易。

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

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

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

    // ...
    return user;
};
{
    // New scope - user is not contained in a shared scope. This is OK.

    var user = CreateUser("email@email.email");
    userManager.AddToRole(user.Id, "Administrator"); 
}