【问题标题】:ASP.NET Core MVC List<Model>.Contains(Model)ASP.NET Core MVC List<Model>.Contains(Model)
【发布时间】:2020-05-12 18:20:44
【问题描述】:

我有这门课:

public class UserSet
{
    public int One { get; set; }
    public string Two { get; set; }
    public string Three { get; set; }
}

还有一个静态类:

public static class AllUsers
{
    public static List<UserSet> Usersc = new List<UserSet>();
}

我总是创建新的UserSet,然后将其存储在Usersc。基本上我是这样做的:

Data.UserSet setupSet = new Data.UserSet()
        {
            One = name,
            Two = OsCislo,
            Three = User.Identity.Name
        };

然后我保存它。

Data.AllUsers.Usersc.Add(setupSet)

现在我想做的是:

  1. 定义设置集
  2. 检查 setupSet 是否在 Usersc 中。
  3. 如果一个(来自我的 setupSet)在 Usersc 中,那么
    3a) 如果 setupSet 在 Userc 中并且一切都相等,则不要做任何事情。
    3b) 如果有所不同,则删除 AllUsers 中的旧 UserSet 并插入新的

在代码中它看起来像这样:

Data.UserSet setupSet = new Data.UserSet()
        {
            One = name,
            Two = OsCislo,
            Three = User.Identity.Name
        };

if (Data.AllUsers.Usersc.Select(s => s.One).ToList().Contains(User.Identity.Name))
{
    // Always returns false for some reason
    if (!Data.AllUser.Usersc.Contains(setupSet))
    {
        Data.AllUsers.Usersc.Remove(Data.AllUsers.Usersc.Where(s => s.One == User.Identity.Name).ToList().First());
        Data.AllUsers.Usersc.Add(setupSet);
    }
}
else
{
    Data.AllUsers.Usersc.Add(setupSet);
}

如您所见,问题出在我的 if 语句中,我尝试获取 setupSet 是否在 Usersc 中,但由于某些奇怪的原因,即使 setupSet 应该在其中,它总是返回 false。

【问题讨论】:

    标签: c# asp.net asp.net-mvc asp.net-core c#-4.0


    【解决方案1】:

    这是因为您的代码行 Data.AllUser.Usersc.Contains(setupSec) 比较引用 - 而不是列表中对象的属性值。

    您在顶部创建 setupSet 对象而不将其添加到列表中 - 因此此列表不包含它。尽管两个对象具有完全相同的 .net 属性值,但它们是两个不同的对象。因此 list.Contains() 返回 false。

    所以解决你的问题有两种方法:

    1. 不要使用 List 的 Contains() 方法 - 并使用 LINQ 表达式比较对您理解 UserSet 类的 2 个对象的相等性至关重要的属性

    2. 绝对更好 - 在您的 UserSet 类中实现 Equals 方法,该方法将告诉 CLI 如果涉及到您的类,您将什么理解为 EQUAL。

    看看下面的代码(请记住这是一个幼稚的实现):

    void Main()
    {
        var myList = new List<SomeClass>();
    
        var o1 = new SomeClass{SomeProperty = "foo"};
    
        myList.Add(o1);
    
        var o2 = new SomeClass{SomeProperty = "foo"};
    
        if(myList.Contains(o2))
        {
            "List Contains element".Dump();
        }
        else{
            "List does not contain element".Dump();
        }
    
    }
    
    
    
    private class SomeClass{
        public string SomeProperty {get;set;}
    
        public override bool Equals(object obj)
        {
            var casted = obj as SomeClass;
            if(casted == null) return false;
            if(string.Equals(casted.SomeProperty, this.SomeProperty)) return true;
            return false;
        }
    }
    

    在这里,我通过覆盖 {public bool Equals(object obj)} 方法告诉 .NET,我的 SomeClass 的 2 个实例相等对我意味着什么。

    在该方法中,如果 SomeProperty 的值相同,我会写 2 个对象相等。

    if(string.Equals(casted.SomeProperty, this.SomeProperty)) return true; 
    

    因此,在控制台中,我可以看到“列表包含元素”。如果您删除该覆盖 Equal,控制台将显示“列表不包含该元素”。

    最后但同样重要的是,正如 Blindy 所写 - 使用线程安全集合。这将使您的示例更好(但是我不认为线程是您描述的问题)。

    您还可以深入研究 Entity Framework 中的内存数据库 - 您不必使用静态元素集合创建该静态类(我相信这是缓存数据库的模拟)。超级简单

    var options = new DbContextOptionsBuilder<ApplicationDbContext>()
                        .UseInMemoryDatabase(databaseName: "My_DB")
                        .Options;
                var context = new ApplicationDbContext(options);
    

    【讨论】:

    • 感谢您的解决!我试图解决它大约 2 天。
    【解决方案2】:

    即使 setupSet 也应该在里面

    static 在任何类型的 Asp.Net 项目中很少使用是有原因的:有多个线程处理您的请求,如果它们都在为同一个 List&lt;&gt; 争吵,那就是灾难的根源.

    要么使用同步集合(如ConcurrentSet&lt;&gt;ConcurrentBag&lt;&gt;),要么使用粗略的锁定机制,或者某种东西 以确保您不会践踏另一个线程的列表访问权限。

    或者更好的是,使用数据库来存储数据。这就是它的用途,而且大多数 DBMS 都是事务性的,因此它们可以为您安全地处理多线程访问。

    【讨论】:

    • 感谢您的建议。我会尝试实现这样的东西。
    猜你喜欢
    • 2017-12-01
    • 2023-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多