【问题标题】:Correct method of retrieving data from another class thats wrapped in using statement从包装在 using 语句中的另一个类中检索数据的正确方法
【发布时间】:2014-03-24 19:40:34
【问题描述】:

我遇到了异常

无法访问已处置的对象。

我知道我遇到了这个异常,因为对象在它有机会返回结果之前已经被释放。我想知道的是检索对象的正确方法。我的代码中可能有不必要的步骤,并且可能做错了吗?

我的主类中有一个按钮单击事件。它调用下面代码中显示的方法。 GetADComputer 方法位于另一个名为ActiveDirectory.cs 的类中。尝试访问已处置对象的结果时出现异常。

public static PrincipalSearchResult<Principal> GetADComputer(string pcName)
{
    using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
    {
        using (ComputerPrincipal computer = new ComputerPrincipal(ctx))
        {
            computer.Name = String.Format("*{0}*", pcName);

            using (PrincipalSearcher searcher = new PrincipalSearcher())
            {
                searcher.QueryFilter = computer;
                return searcher.FindAll();
            }
        }
    }            
}    

【问题讨论】:

  • 我没用过PrincipalSearcher,但你考虑过用return searcher.FindAll().ToList();返回List&lt;Principal&gt;吗?假设 Principal 对象是完全物化的,那应该不再需要上下文了......
  • @JonSkeet Principal 对象没有完全实现,DirectoryServices 延迟加载属性。 (你也许可以改变它,但我不知道如何)
  • @ScottChamberlain: 嘘 :(
  • 这是@JonSkeet!哈哈。谢谢回复。使用列表方法是可行的,但我正在研究@ScottC 关于对象物化的说法。

标签: c# winforms using-statement


【解决方案1】:

问题是 DirectoryServices 对其信息使用延迟加载,因此由于您关闭了上下文,您无法再从 Principal 检索信息。

您有两个选择,要么将PrincipalContext 传递给查询,因此当您返回时它不会超出范围:

public static DoSomthing()
{
    using(var ctx = new PrincipalContext(ContextType.Domain))
    using(PrincipalSearchResult<Principal> result = GetADComputer("some Name", ctx))
    {
        //do something with the result here.
    }
}

public static PrincipalSearchResult<Principal> GetADComputer(string pcName, PrincipalContext ctx)
{
    using (var computer = new ComputerPrincipal(ctx))
    {
        computer.Name = String.Format("*{0}*", pcName);

        using (var searcher = new PrincipalSearcher())
        {
            searcher.QueryFilter = computer;
            return searcher.FindAll();
        }
    }
} 

或者您需要将结果转换为不依赖延迟加载的内容,以便您可以关闭与目录服务器的连接。

public static List<ComputerInfo> GetADComputer(string pcName, PrincipalContext ctx)
{
    using (var computer = new ComputerPrincipal(ctx))
    {
        computer.Name = String.Format("*{0}*", pcName);

        using (var searcher = new PrincipalSearcher())
        {
            searcher.QueryFilter = computer;
            using (PrincipalSearchResult<Principal> result = searcher.FindAll())
            {
                return result.Select(p=> new ComputerInfo(p.Name, p.SID)).ToList();
            }
        }
    }
} 

public class ComputerInfo
{
    public ComputerInfo(string name, SecurityIdentifier sid)
    {
        Name = name;
        SID = sid;
    }

    public string Name {get; set;}
    public SecurityIdentifier SID {get; set;}
}

【讨论】:

  • 这很好用!我为我拥有的另一种 AD 查询方法尝试了这种方法。另一种方法使用 System.DirectoryServices 类并抛出“无法访问已处置的对象”。例外。您的回复是否仅适用于我使用 System.DirectoryServices.AccountManagement 类的示例代码?
  • @HiTech 这是相同的潜在问题,要么通过将上下文作为参数传递来保持上下文打开,要么将返回对象转换为不依赖上下文的对象。
猜你喜欢
  • 1970-01-01
  • 2023-02-13
  • 2014-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-17
  • 1970-01-01
相关资源
最近更新 更多