2010-01-08 46 views
5

tôi có khai báo lớp sau:Tại sao không hỗ trợ một đối tượng với giao diện như một tham số?

public class EntityTag : BaseEntity, ITaggable 

Tôi có một phương pháp helper Html:

public static string TagCloud(this HtmlHelper html, IQueryable<ITaggable> taggables, 
    int numberOfStyleVariations, string divId) 

Đây là ascx ASP.NET MVC của tôi:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IQueryable<EDN.MVC.Models.EntityTag>>" %> 
<%@Import Namespace="EDN.MVC.Helpers" %> 
<%= Html.TagCloud(Model, 6, "entity-tags") %> 

Khi tôi vượt qua trong một bộ sưu tập IQueryable cho ascx, tôi nhận được lỗi này:

Compil er Thông báo lỗi: CS1928: 'System.Web.Mvc.HtmlHelper>' không chứa định nghĩa cho 'TagCloud' và phương thức mở rộng tốt nhất quá tải 'EDN.MVC.Helpers.EdnHelpers.TagCloud (System.Web.Mvc.HtmlHelper, System.Linq.IQueryable, int, string)' có một số đối số không hợp lệ

Nếu tôi cố gắng để chuyển đổi một cách rõ ràng bộ sưu tập tượng với điều này:

public static string TagCloud(this HtmlHelper html, IQueryable<Object> taggables, int numberOfStyleVariations, string divId) 
    { 
     var tags = new List<ITaggable>(); 
     foreach (var obj in taggables) 
     { 
      tags.Add(obj as ITaggable); 
     } 
     return TagCloud(html, tags.AsQueryable(), numberOfStyleVariations, divId); 
    } 

tôi nhận được cùng một lỗi - các giá trị tôi đi qua không thích bởi trình biên dịch.

Lớp EntityTag của tôi có được hỗ trợ tự động như IQueryable không? Tôi đang thiếu gì? Nó phải là một cái gì đó hiển nhiên. (Tôi hy vọng).

+0

ITaggable có thể kế thừa từ IQueryable không? –

+0

Thông số mô hình bạn đang truyền là gì? Tôi đoán rằng tham số không thể được chuyển đổi thành IQueryable, vì một lý do nào đó. –

+0

Tony: EntityTag xuống từ BaseEntity và thực hiện ITaggable –

Trả lời

5

Về cơ bản, bạn đang cố gắng để vượt qua một đối tượng của loại phi generic IQueryable đến một phương pháp mà chấp nhận chung IQueryable<ITaggable>, mà trình biên dịch có thể không phải là "trận đấu", kết quả trong CS1928 (vì có hai loại, trên thực tế, khác nhau).

Trong quá tải của bạn mà chấp nhận một IQueryable<object> (vốn đã thực hiện chuyển đổi cần thiết để một danh sách chung), bạn chỉ cần gọi phiên bản generic của AsQueryable thay cho một phi chung chung, như vậy:

public static string TagCloud(this HtmlHelper html, IQueryable taggables, int numberOfStyleVariations, string divId) 
{ 
    var tags = new List<ITaggable>(); 
    foreach (var obj in taggables) 
    { 
     tags.Add(obj as ITaggable); 
    } 
    return TagCloud(html, tags.AsQueryable<ITaggable>(), numberOfStyleVariations, divId); 
} 

Cho phép tôi thêm, rằng, IQueryable<T> có nguồn gốc từ IQueryable, có nghĩa là không phải tất cả các đối tượng IQueryableIQueryable<T>, do đó thực hiện chuyển đổi cần thiết. Nếu tình huống bị đảo ngược, tức là phương thức trợ giúp "thực" của bạn đã được xác định để xử lý các đối tượng IQueryable, thì chắc chắn bạn sẽ không gặp vấn đề khi chuyển một phương thức đó (vì tất cả các đối tượng IQueryable<T>, trên thực tế, IQueryable).

Per Craig Stuntz, một giải pháp thanh lịch hơn, sử dụng các tính năng LINQ: <%= Html.TagCloud(Model.Select(t => (ITaggable)t), 6, "entity-tags") %>. Bạn cũng có thể sử dụng <%= Html.TagCloud(Model.Cast<ITaggable>(), 6, "entity-tags") %> nếu nhà cung cấp có thể truy vấn của bạn hỗ trợ nó.

+1

Điều này phù hợp với nguyên nhân (+1), nhưng tôi muốn sử dụng một giải pháp đơn giản hơn: '<% = Html.TagCloud (Model.Select (t => (ITaggable) t), 6, "thẻ tổ chức")%> '. Bạn cũng có thể sử dụng 'IEnumerable .Cast() 'nếu nhà cung cấp có thể truy vấn của bạn hỗ trợ nó. –

+0

Cảm ơn bạn đã trả lời. Thật không may, phiên bản thứ hai không bao giờ được lựa chọn bởi trình biên dịch khi phiên bản dựa trên giao diện cũng được khai báo, ngay cả khi tôi cast trong ascx. Nó vẫn đánh tôi như là đặc biệt mà trình biên dịch không thể xác định rằng EntityTag có giao diện ITaggable, mặc dù. Tóm lại, tôi vẫn đang tìm một giải pháp hợp lý ... –

+0

Cảm ơn, Craig - đó là loại giải pháp đúc tao nhã mà tôi đang tìm kiếm vì trình biên dịch không tự động truyền cho tôi. Điều đó hiệu quả. Nếu bạn chuyển đổi nhận xét của bạn thành một câu trả lời, tôi sẽ chấp nhận nó là giải pháp. –

1

lớp EntityTag của bạn là IQueryable, tuy nhiên trình biên dịch không biết rằng danh sách các thẻ thực sự là một danh sách các EntityTag đối tượng, nó chỉ biết rằng đó là một danh sách các đối tượng thực hiện ITaggable, mà có lẽ isn 't IQueryable.

2

C# 4.0 sẽ hỗ trợ. Tìm kiếm "Hiệp phương sai và Contravariance trong C# 4"

Các vấn đề liên quan