2012-03-05 42 views
5

Tôi đang cố gắng để hiểu tại sao diễn viên này không làm việc:Tại sao ví dụ này không hoạt động?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace CastTest { 

    class Foo {} 

    // I want to use this kind of like a typedef, to avoid writing List<Foo> everywhere. 
    class FooList : List<Foo> {} 

    class Program { 
     static void Main(string[] args) { 
      FooList list = (FooList) Program.GetFooList(); 
     } 

     // Suppose this is some library method, and i don't have control over the return type 
     static List<Foo> GetFooList() { 
      return new List<Foo>(); 
     } 
    } 
} 

này tạo ra một lỗi runtime:

InvalidCastException: Unable to cast object of type 'System.Collections.Generic.List`1[CastTest.Foo]' to type 'CastTest.FooList'.

bất cứ ai có thể giải thích tại sao điều này không làm việc, và cho dù tôi có thể nhận được xung quanh bằng cách nào đó?

+0

Dòng nào tạo lỗi? – ChrisF

+0

Điều gì là đúng để nói: Một FooList là một Danh sách , hoặc một Danh sách là một FooList? –

+0

@AnthonyPegram Trước đây. – hvd

Trả lời

5

Bạn không thể tự động truyền từ lớp cha sang lớp dẫn xuất: chỉ vì đối tượng bạn đang cố truyền là List<Foo> không nhất thiết phải là FooList.

Check-out:

http://social.msdn.microsoft.com/Forums/is/csharplanguage/thread/f7362ba9-48cd-49eb-9c65-d91355a3daee

Bạn có thể viết một nhà điều hành có thể chuyển đổi một List<Foo> đến một FooList, có lẽ sử dụng AddRange để điền giá trị, chẳng hạn như:

class FooList 
{ 
public explicit operator FooList(List<Foo> arg) 
{ 
    FooList result = new FooList(); 
    result.AddRange(arg); 
    return result; 
    } 
} 

Ngoài ra, có thể tốt hơn nếu chỉ sử dụng một bí danh using: http://msdn.microsoft.com/en-us/library/sf0df423(v=vs.80).aspx

using FooList = List<Foo>; 

Bằng cách này bạn không thực sự đi qua các lớp học không cần thiết.

+1

Có thể downcast? – user1096188

+0

Cảm ơn, và sử dụng 'using' là một mẹo hay ... vấn đề duy nhất của tôi với nó (và lý do tôi cố gắng sử dụng các lớp để giải quyết nó) là một' using' không thể phụ thuộc vào kiểu được định nghĩa trong một ' sử dụng'. Ghép nối rằng với thực tế là 'using' cần phải sử dụng một tên đầy đủ (nghĩa là bạn cần sử dụng' System.Collections.Generic.List' thay vì 'List') và khai báo' using' được thực sự nhanh chóng. – Eric

7

Chỉ vì FooList của bạn là Danh sách không tạo Danh sách FooList.

4

Phương pháp này:

static List<Foo> GetFooList() { 
    return new List<Foo>(); 
} 

... không trả lại một FooList. Mã của bạn có hiệu quả như sau:

FooList list = (FooList) new List<Foo>(); 

Điều đó sẽ không hoạt động. Nó không hợp lệ như:

string x = (string) new object(); 

Bạn sẽ không mong đợi điều đó có hiệu quả không? Vậy tại sao phiên bản FooList của bạn hoạt động?

2

Gần nhất C# có một typedef được gọi là sử dụng chỉ thị bí danh:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace CastTest { 
    using FooList = List<Foo>; 

    class Foo {} 

    class Program { 
     static void Main(string[] args) { 
      FooList list = Program.GetFooList(); 
     } 

     // Suppose this is some library method, and i don't have control over the return type 
     static List<Foo> GetFooList() { 
      return new List<Foo>(); 
     } 
    } 
} 

Những gì bạn có tạo ra một lớp có nguồn gốc FooList, nhưng điều này sẽ tạo ra một bí danh FooList. Nó không tương thích với List<Foo>, nó List<Foo>.

1

Vì bạn biết rằng FooList thực tế chỉ là một tên khác cho số List<Foo>, điều này có vẻ lạ. Nhưng với điều kiện, FooList có thể chứa các thành viên, nó sẽ trở thành apparant mà trình biên dịch không cho phép diễn viên. Hãy tưởng tượng bạn sau này giới thiệu một phương pháp (Bar()) trên FooList. Phương thức này không có mặt trên List<Foo> và hệ thống kiểu sẽ đơn giản phá vỡ nếu việc gán (hoặc bỏ) được cho phép.

2

Vì không phải tất cả Danh sách đều là FooList. Ví dụ, tôi có thể có:

public class AnotherFooList : List<Foo> 
{ 
    public object AdditionalPropery {get; set; } 
} 

Nó quá thừa hưởng từ Danh sách nhưng không giống như một FooList và FooList là không giống như nó.

1

Bạn không thể phát triển; nhưng bạn có thể tạo một phiên bản mới của FooList và nội dung của FooList và nội dung của nó là

class Foo { } 

    // I want to use this kind of like a typedef, to avoid writing List<Foo> everywhere. 
    class FooList : List<Foo> {} 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      FooList l = new FooList(); 
      l.AddRange(GetFooList().Select(foo => foo)); 

      Console.ReadLine(); 
     } 

     // Suppose this is some library method, and i don't have control over the return type 
     static List<Foo> GetFooList() 
     { 
      return new List<Foo>(); 
     } 
    } 
Các vấn đề liên quan