【问题标题】:Access Properties of Derived Classes from an Interface in Linq Query?从 Linq 查询中的接口访问派生类的属性?
【发布时间】:2017-02-22 15:36:15
【问题描述】:

我创建了一个具有两个派生类的接口,如下面的代码 sn-ps 所示,我想在 Linq 查询中访问这些派生类的成员,但我无法做到。

模型类结构:

public interface IDirDetails
{   
}
public class DirectoryDetails: IDirDetails
{
    public string[] PathElements { get; set; }
    public string[] ApplicationList { get; set; }

    public List<DirectoryItemInfo> Items { get; set; }
}
public class DirectoryItemInfo: IDirDetails
{
    public string FileName { get; set; }
    public string FileType { get; set; }
    public string FileSize { get; set; }
    public string FileIcon { get; set; }
    public DateTime FileModified { get; set; }
    public string FilePath { get; set; }
}

我试图访问这些成员的代码表单:

List<IDirDetails> data = LoadData();                   
int totalRecords = data.Count;

if (!string.IsNullOrEmpty(search) && !string.IsNullOrWhiteSpace(search))
{
    // Apply search
    data = data.Where(p => p.FileName.ToString().ToLower().Contains(search.ToLower()) ||  //not allowing to access FileName
                           p.FileSize.ToLower().Contains(search.ToLower()) ||               //not allowing to access FileSize
                           p.FileModified.ToString().ToLower().Contains(search.ToLower())).ToList(); //not allowing to accessFileModified
}   

下面是我如何在LoadData() 中为这些类设置值

public List<IDirDetails> LoadData()
{
    string userName = HttpContext.User.Identity.Name;
    var user = _context.Users.FirstOrDefault(m => m.UserName == userName);           
    string[] appList = null;
    var allDirDetails = new List<IDirDetails>(); //obj of an Interface
    var allAppExist = _context.UserApplications.Any(ua => ua.AppId == 17 && ua.UserId == user.Id);

    appList = (from a in _context.Applications
               join ua in _context.UserApplications on a.Id equals ua.AppId
               where ua.UserId == user.Id
               select a.AppName).ToArray();

    DirectoryDetails dirDetails = new DirectoryDetails();
    dirDetails.ApplicationList = appList;

    List<DirectoryItemInfo> dirItems = new List<DirectoryItemInfo>();
    dirDetails.Items = dirItems;

    allDirDetails.Add(dirDetails);  // adding values into DirectoryDetails

    string requestPath = Request.Path.Value;

    string[] requestPathParts = requestPath.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
    dirDetails.PathElements = requestPathParts;

    var aapId = _context.Applications.FirstOrDefault(a => a.AppName == requestPathParts[0].ToString());

    string[] physicalPaths = (from ap in _context.ApplicationPathElements
                              join a in _context.Applications on ap.AppId equals a.Id
                              where a.Id == aapId.Id
                              select ap.AppPathElement).ToArray();
    if (physicalPaths != null && physicalPaths.Length > 0)
    {
        foreach (string indexPath in physicalPaths)
        {
            DirectoryItemInfo details = GetDirectoryInfo(indexPath, indexPath + "/", DateTime.MinValue);        
            allDirDetails.Add(details); // adding values into DirectoryItemInfo
        }
    }            
    return allDirDetails;
}

有人可以建议我应该如何从接口访问派生类的必需成员吗?

【问题讨论】:

    标签: c# linq asp.net-core-webapi


    【解决方案1】:

    对您的问题的简单回答是:只需投射它

    data = data.Cast<DirectoryItemInfo>().Where(p => p.FileName.ToString().ToLower().Contains(search.ToLower()) ||  
                           p.FileSize.ToLower().Contains(search.ToLower()) ||             
                           p.FileModified.ToString().ToLower().Contains(search.ToLower())).ToList(); 
    

    或使用OfType

    data = data.OfType<DirectoryItemInfo>().Where(p => p.FileName.ToString().ToLower().Contains(search.ToLower()) ||  
                           p.FileSize.ToLower().Contains(search.ToLower()) ||             
                           p.FileModified.ToString().ToLower().Contains(search.ToLower())).ToList(); 
    

    正确答案是:您的模型有问题。您不需要接口列表,而是特定类型的列表,或者您应该将这些属性移至接口。

    例如,您的 LoadData 方法返回接口列表,但在您的示例中,您将其用作特定类的列表。您可以将其更改为:

    public List<T> LoadData<T>()  where T:IDirDetails
    {   
        // return specific List
    }
    

    之后你可以这样称呼它:

    List<DirectoryItemInfo> data = LoadData<DirectoryItemInfo>();
    

    而且你不需要演员表。在LoadData 的某个地方,您应该决定要返回哪些元素。

    【讨论】:

    • 感谢您的回答先生,您能提出正确的方法来实现这些吗?
    • @RahulNagrale 我没有看到你的整个代码,我在答案中提出了一个建议,但这真的取决于你到底在做什么。
    • 当我从LoadData()返回List&lt;IDirDetails&gt;时显示错误,错误:CS0029 Cannot implicitly convert type 'System.Collections.Generic.List&lt;IL_LogViewer.Models.IDirDetails&gt;' to 'System.Collections.Generic.List&lt;T&gt;'
    • @RahulNagrale 确实如此。您可以返回 DirectoryItemInfo 列表并将其用作 DirectoryItemInfo。或者您返回接口列表并将其用作接口。
    • 先生,我遵循了您在答案中提供的更新代码,即将LoadData() 修改为public List&lt;T&gt; LoadData&lt;T&gt;() where T:IDirDetails,现在还返回List&lt;DirectoryItemInfo&gt;,但仍然显示错误。请查看错误:CS0029 Cannot implicitly convert type 'System.Collections.Generic.List&lt;IL_LogViewer.Models.DirectoryItemInfo&gt;' to 'System.Collections.Generic.List&lt;T&gt;'
    【解决方案2】:

    您可以使用 'OfType' 方法从 'DirectoryItemInfo' 类型的 'data' 列表中获取所有项目,并将 'Where' 的结果转换回 'IDirDetails' 列表。

    data = data.OfType<DirectoryItemInfo>()
               .Where(p => 
                      p.FileName.ToString().ToLower().Contains(search.ToLower()) ||
                      p.FileSize.ToLower().Contains(search.ToLower()) ||  
                      p.FileModified.ToString().ToLower().Contains(search.ToLower()))
               .ToList<IDirDetails>();
    

    【讨论】:

      【解决方案3】:

      您只能访问由您的界面定义的那些成员。如果您需要访问该接口的具体实现的成员,您将需要具体实现的实例(在您的情况下,是DirectoryDetailDirectoryItemInfo 的实例。

      您可以像其他成员所说的那样通过强制转换来做一些事情,但您仍然以某种方式访问​​具体实现的实例。

      【讨论】:

        【解决方案4】:

        使用OfType过滤类型

        List<IDirDetails> data = LoadData();                   
        int totalRecords = data.Count;
        
        if (!string.IsNullOrEmpty(search) && !string.IsNullOrWhiteSpace(search))
        {
            // Apply search
            data = data.OfType<DirectoryItemInfo>().Where(p => p.FileName.ToString().ToLower().Contains(search.ToLower()) ||  
                                   p.FileSize.ToLower().Contains(search.ToLower()) ||               
                                   p.FileModified.ToString().ToLower().Contains(search.ToLower())).Cast<IDirDetails>().ToList(); 
        }   
        

        【讨论】:

        • 如果列表中有DirectoryDetailsCast 将不起作用。
        猜你喜欢
        • 1970-01-01
        • 2014-12-28
        • 1970-01-01
        • 1970-01-01
        • 2018-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多