2012-03-12 36 views
9

Tôi muốn có chức năng in chung ... PrintGeneric (T) ... trong trường hợp sau, tôi đang thiếu gì?C#: Truyền đối tượng chung

Như mọi khi giúp đỡ của bạn/cái nhìn sâu sắc được đánh giá cao ...

public interface ITest 
{} 

public class MyClass1 : ITest 
{ 
    public string myvar = "hello 1"; 
} 

public class MyClass2 : ITest 
{ 
    public string myvar = "hello 2"; 
} 

class DoSomethingClass 
{ 

    static void Main() 
    { 
     MyClass1 test1 = new MyClass1(); 
     MyClass2 test2 = new MyClass2(); 

     Console.WriteLine(test1.myvar); 
     Console.WriteLine(test2.myvar);    
     Console.WriteLine(test1.GetType()); 

     PrintGeneric(test1); 
     PrintGeneric<test2.GetType()>(test2); 
    } 

    // following doesn't compile 
    public void PrintGeneric<T>(T test) 
    { 
     Console.WriteLine("Generic : " + test.myvar); 
    } 
} 
+1

'var' không thể là một tên biến vì nó là một từ khóa. Bạn có thể hiển thị mã thực của bạn không. –

+3

@AshBurlaczenko Không chính xác. 'var' là một từ khóa theo ngữ cảnh được thêm vào trong C# 3.0. Bạn có thể sử dụng nó làm tên định danh. Tương tự, bạn có thể sử dụng 'yield',' select', 'from', vv làm tên định danh trong hầu hết các ngữ cảnh. –

+0

thực sự "var" đã hoạt động mà không cần sử dụng Console.WriteLine ... nhưng đó là điều xấu của tôi khi sử dụng từ khóa làm tên định danh ... – user1229895

Trả lời

19

Nó không biên dịch vì T có thể là bất cứ thứ gì và không phải mọi thứ đều có trường myvar.

Bạn có thể làm myvar một tài sản trên ITest:

public ITest 
{ 
    string myvar{get;} 
} 

và thực hiện nó trên lớp như một thuộc tính:

public class MyClass1 : ITest 
{ 
    public string myvar{ get { return "hello 1"; } } 
} 

và sau đó đặt một hạn chế chung về phương pháp của bạn:

public void PrintGeneric<T>(T test) where T : ITest 
{ 
    Console.WriteLine("Generic : " + test.myvar); 
} 

nhưng trong trường hợp đó phải trung thực bạn tốt hơn hết ju st đi qua trong một ITest:

public void PrintGeneric(ITest test) 
{ 
    Console.WriteLine("Generic : " + test.myvar); 
} 
+0

Tôi đã thêm thuộc tính vào ITest, nhưng sau đó nó nói với tôi rằng tôi cần phải thực hiện nó trong MyClass1/MyClass2 ... mà có ý nghĩa, nhưng sau đó tôi nhận được một lỗi nói rằng nó đã có một định nghĩa cho myvar – user1229895

+0

Oh yeah, bạn cần phải thay đổi các lĩnh vực để được tài sản trong triển khai các lớp học. Đã cập nhật câu trả lời của tôi để hiển thị cho bạn. – jonnystoten

+0

tôi đã thử PrintGeneric (test2) trong Main cho generic và nhận 'Chỉ gán, gọi, tăng, giảm được sử dụng như một câu lệnh' và PrintGeneric (test1) cho PrintGeneric (kiểm tra ITest). .và nhận được một "Tham chiếu đối tượng là bắt buộc đối với trường không tĩnh" – user1229895

0

thử

public void PrintGeneric<T>(T test) where T: ITest 
{ 
    Console.WriteLine("Generic : " + [email protected]); 
} 

như @Ash Burlaczenko đã nói bạn không thể đặt tên cho một biến sau khi một từ khóa, nếu bạn muốn điều này reallllly tiền tố có biểu tượng @ để thoát khỏi từ khóa

+1

Điều này sẽ không hoạt động, 'ITest' không có thành viên có tên' var'. –

+0

Chỉ đi làm nếu ITest chỉ định thuộc tính var, tất nhiên. Tôi không chắc chắn nó trong ví dụ. –

+0

vâng quyền của bạn cần được thêm vào ITest –

2

Trong phương pháp chung của bạn, T chỉ là một trình giữ chỗ cho một loại. Tuy nhiên, trình biên dịch không cho biết bất cứ điều gì về loại bê tông (s) đang được sử dụng thời gian chạy, do đó, nó không thể giả định rằng họ sẽ có một thành viên var.

Cách thông thường để phá vỡ này là thêm một loại hạn chế chung để khai phương pháp của bạn để đảm bảo rằng các loại sử dụng thực hiện một giao diện cụ thể (trong trường hợp của bạn, nó có thể là ITest):

public void PrintGeneric<T>(T test) where T : ITest 

Sau đó, , các thành viên của giao diện đó sẽ có sẵn trực tiếp bên trong phương thức. Tuy nhiên, ITest của bạn hiện đang trống, bạn cần khai báo các thông tin phổ biến ở đó để cho phép sử dụng nó trong phương thức.

2

Bạn sẽ phải cung cấp thêm thông tin về loại generic T. Trong phương pháp PrintGeneric hiện tại của bạn, T cũng có thể là string, không có thành viên var.

Bạn có thể muốn thay đổi var để một tài sản chứ không phải là một lĩnh vực

public interface ITest 
{ 
    string var { get; } 
} 

Và thêm một hạn chế where T: ITest với phương pháp PrintGeneric.

6

Bạn đang thiếu ít nhất một vài điều:

  • Trừ khi bạn đang sử dụng phản chiếu, các đối số loại cần phải được biết đến tại thời gian biên dịch, vì vậy bạn không thể sử dụng

    PrintGeneric<test2.GetType()> 
    

    ... mặc dù trong trường hợp này bạn không cần phải nào

  • PrintGeneric không biết gì về T vào lúc này, vì vậy trình biên dịch c an't tìm thấy một thành viên gọi là T

Options:

  • Đặt một tài sản trong giao diện ITest, và thay đổi PrintGeneric để chế ngự T:

    public void PrintGeneric<T>(T test) where T : ITest 
    { 
        Console.WriteLine("Generic : " + test.PropertyFromInterface); 
    } 
    
  • Đặt một bất động sản trong giao diện ITest và loại bỏ hoàn toàn generics:

    public void PrintGeneric(ITest test) 
    { 
        Console.WriteLine("Property : " + test.PropertyFromInterface); 
    } 
    
  • Sử dụng gõ năng động thay vì Generics nếu bạn đang sử dụng C# 4

+1

Typo trong đoạn mã thứ hai của bạn có Jon? Bạn nói loại bỏ generics nhưng vẫn còn một trên phương pháp? –

+2

@SteveHaigh: Doh, đó là những gì tôi nhận được để gõ và nói chuyện trên điện thoại cùng một lúc. Cố định, cảm ơn. –

+0

thử tùy chọn đầu tiên ... Tôi thêm "chuỗi myvar {get;}" vào ITest ... nhưng gặp lỗi khi nói MyClass1/MyClass2 không triển khai thành viên Giao diện 'ITest.myvar' ... thêm "chuỗi myvar {get;} "vào MyClass1/MyClass2 dẫn đến lỗi biên dịch nói rằng nó đã được định nghĩa? – user1229895

1

Bạn cần phải xác định một cái gì đó trong giao diện, chẳng hạn như:

public interface ITest 
{ 
    string Name { get; } 
} 

Triển khai ITest trong c của bạn cô gái trẻ:

public class MyClass1 : ITest 
{ 
    public string Name { get { return "Test1"; } } 
} 

public class MyClass2 : ITest 
{ 
    public string Name { get { return "Test2"; } } 
} 

Sau đó, hạn chế chung Print chức năng của bạn, để ITest:

public void Print<T>(T test) where T : ITest 
{ 
} 
+0

Xem trả lời của tôi về bình luận của Ash cho câu hỏi. Bạn có thể sử dụng 'var' làm tên định danh, giống như' yield', vv, mặc dù đó có lẽ không phải là một ý tưởng tuyệt vời. Đó là một từ khóa theo ngữ cảnh. Hãy thử 'int var;' để tự xác minh. –

+0

@MehrdadAfshari, ah .. Tôi không biết điều đó. Vâng, hôm nay tôi đã học được. Nhưng có, nó không phải là một cái gì đó tôi đã bao giờ thực sự làm :) –

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