2012-07-23 35 views
5

Tôi cố gắng để tạo ra một lớp generic:T không chứa các định nghĩa cho RowKey

public class ClassName<T> 
{ 
    public T AccessEntity(string id) 
    { 
     return (from e in ServiceContext.CreateQuery<T>(TableName) 
       where e.RowKey == id // error here! 
       select e).FirstOrDefault(); 
    } 
} 

Trong mã này tôi nhận được lỗi rằng:

T không chứa các định nghĩa cho RowKey

nhưng các tham số sẽ thay thế T lúc chạy có định nghĩa của RowKey. Có lẽ vì complier không nhận được định nghĩa cho RowKey trong T tại thời gian biên dịch, đó là lý do tại sao tôi nhận được lỗi này. Ai có thể cho tôi biết làm thế nào để giải quyết vấn đề này?

+0

Như một lời nhận xét - Tôi upvoted một trong những câu trả lời đúng: trình biên dịch không quan tâm những gì T sẽ về sau. Nó quan tâm đến những gì nó BIẾT tại thời gian biên dịch, có nghĩa là bạn CÓ THỂ tạo ClassName và Dumbo không có lỗi RowKey ->. Adda constraint;) – TomTom

+0

Pro minh họa điểm của TomTom: trong C# bạn có thể viết một kiểu * tại thời gian chạy *, và gọi kiểu generic cho kiểu mới - miễn là nó đáp ứng ràng buộc, nó sẽ hoạt động. Điều này rất khác với các mẫu C++. –

Trả lời

11

Để làm điều đó bạn sẽ cần một chế giao diện:

interface IHazRowKey { 
    string RowKey { get; } 
} 

Và chỉ định hạn chế này:

public class classname<T> where T : IHazRowKey {...} 

Và rõ : IHazRowKey trên mỗi hiện thực:

public class Foo : IHazRowKey {....} 

Các thành viên hiện tại RowKey phải khớp với nó (giả sử tôi t là một thuộc tính, không phải là một trường), vì vậy bạn không cần phải thêm bất kỳ mã bổ sung nào khác. Nếu nó thực sự là một trường (mà nó không nên là, IMO) thì:

public class Foo : IHazRowKey { 
    string HazRowKey.RowKey { get { return this.RowKey; } } 
    ... 
} 
+3

Không phải là ICanHazRowKey phải không? :) –

+0

cảm ơn cho câu trả lời, nhưng lớp mà tôi đang thực hiện như một lớp chung đã lái từ lớp khác, xin lỗi vì không đề cập đến điều này trong câu hỏi. Có nghĩa là nó là một cái gì đó như: public class ClassName : Base –

+2

@Tom không thay đổi bất cứ điều gì; bạn được phép thừa kế nhiều giao diện và thừa kế lớp đơn, –

1
class YourClass // or extract an interface 
{ 
    public string RowKey { get; set; } 
} 

class YourGeneric<T> where T : YourClass 
{ 
    // now T is strongly-typed class containing the property requested 
} 
3

Bạn cần phải xác định constraint để giải quyết này:

public interface IHasRowKey 
{ 
    string RowKey {get;} 
} 

public class classname<T> where T : IHasRowKey 
{ 

} 
8

Có sự khác biệt lớn giữa C++ templates và C Generics #: nó không có vấn đề gì lớp bạn vượt qua để nhanh chóng các chung chung, nếu trình biên dịch không biết về một phương thức trên T tại thời điểm biên dịch lớp hoặc phương thức chung của bạn, nó sẽ cho bạn một lỗi. Điều này là do C# cần một khả năng để biên dịch mã chung một cách riêng biệt với các vị trí của nó instantiation (nhớ, không có tiêu đề trong C#).

Bạn có thể xác định giao diện và giới hạn T cho nó để sử dụng các thuộc tính và phương thức bên trong một chung chung. Thêm RowKey vào giao diện của bạn và thêm where T : myinterface vào tuyên bố chung của bạn.

0

Trường hợp của tôi không thể sử dụng giao diện để chứa RowKey, vì tôi có hai lớp có thuộc tính và phương pháp khác nhau. Tôi không thể chỉ hợp nhất chúng và đặt các thuộc tính và phương thức này vào một giao diện trình bao bọc hoặc lớp, vì nó mất mục đích sử dụng lớp chung chung. Giải pháp của tôi là sử dụng sự phản chiếu với lớp Generic. Ví dụ .:

public class ClassName<T> { 
    private T _genericType; 
    public ClassName(T t) { 
     _genericType = t; 
    } 

    public void UseGenericType() { 
     // Code below allows you to get RowKey property from your generic 
     // class type param T, cause you can't directly call _genericType.RowKey 
     PropertyInfo rowKeyProp = _genericType.GetType().GetProperty("RowKey"); 
     if(rowKeyProp != null) { // if T has RowKey property, my case different T has different properties and methods 
      string rowKey = rowKeyProp.GetValue(_genericType).ToString(); 
      // Set RowKey property to new value 
      rowKeyProp.setValue(_genericType, "new row key"); 
     } 
    } 
} 

Đây là tài liệu tham khảo để PropertyInfo lớp http://msdn.microsoft.com/en-us/library/System.Reflection.PropertyInfo_methods(v=vs.110).aspx

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