2013-04-04 30 views
2

我有一些具有公共屬性的類,但是,我不能讓它們從基類型(LINQ-to-SQL限制)派生。C#約束可以在沒有基類型的情況下使用嗎?

我想對待他們,好像他們有一個基本類型,但不通過使用反射(性能是關鍵)。

例如:

public class User 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
} 

public class Vehicle 
{ 
    public int Id { get; set; } 
    public string Label { get; set; } 
} 

在這種情況下,我會很高興,如果我有Id屬性可用,不管我手裏拿的類型。

有沒有辦法在C#中,以類似於此:

public static int GetId<T>(T entity) where T // has an int property 'Id' 
{ 
    return entity.Id; 
} 

我想我可以用dynamic,但是,我正在尋找一種方法來限制在編譯時代碼從沒有Id屬性的對象使用此方法。

+2

這些生成的類是什麼?如果是這樣,它們應該以'public partial class Blah ...'的形式生成,這將允許您創建額外的'partial class'文件,這將使您能夠利用提供定義接口的答案。例如,我在使用存儲庫模式時使用了與EF相同的方法。 – 2013-04-04 15:02:17

+0

只是好奇,爲什麼你正在尋找一種方法來限制在編譯時的代碼。 「動態」似乎是最好的方法呢? – 2013-04-04 15:02:54

+0

@CongLong,他不應該選擇'動態',除非這些類是真正關閉修改。鑑於他提到Linq-to-SQL,我懷疑他有更多的選擇,而不是他意識到的。 – 2013-04-04 15:10:34

回答

2

您可以創建一個公共屬性的界面,讓你的類實現它:

public interface IEntity 
{ 
    int Id { get; set; } 
} 

public class User : IEntity 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
} 

public class Vehicle : IEntity 
{ 
    public int Id { get; set; } 
    public string Label { get; set; } 
} 

public static int GetId<T>(T entity) where T : IEntity 
{ 
    return entity.Id; 
} 

您可以簡化GetId這樣的:

public static int GetId(IEntity entity) 
{ 
    return entity.Id; 
} 
4

可以使用接口:

public interface IHasId 
{ 
    int Id { get; } 
} 

public class User : IHasId { ... } 
public class Vehicle : IHasId { ... } 

public static int GetId<T>(T entity) where T : IHasId 
{ 
    return entity.Id; 
} 

但是,如果您無法修改類添加界面e,你將無法做到這一點。沒有編譯時檢查將驗證T上存在的財產。你必須使用反射 - 這很慢,顯然不理想。

0

要麼你需要讓兩個類都實現一個你需要的屬性的接口,並在通用約束中使用它,或者爲每個類型編寫單獨的方法。這是您獲得編譯時安全的唯一方法。

2

沒有辦法保證類型具有給定的成員,而不會限制到通用的基類型或接口。要解決此限制的一種方法是使用lambda訪問值

public static int Use<T>(T value, Func<T, int> getIdFunc) { 
    int id = getIdFunc(value); 
    ... 
} 

Use(new User(), u => u.Id); 
Use(new Vehicle(), v => v.Id); 
1

其他的答案提的接口方法當然是不錯的,但我想以適應您的情況,涉及的LINQ到SQL響應。

但首先,爲解決這個問題標題問

能否C#的約束,而不基本類型使用?

一般來說,答案是否定的。具體而言,您可以使用struct,classnew()作爲約束條件,這些不是技術上的基本類型,它們確實提供了有關如何使用類型的一些指導。這並沒有達到你想要做的水平,也就是將一種方法限制爲具有某種屬性的類型。爲此,您需要限制到特定的接口或基類。

對於您的特定用例,您提到了Linq-to-SQL。如果您使用爲您生成的模型進行工作,那麼您應該有選項來修改這些類,而無需直接修改生成的模型類文件。

你可能有這樣的事情

// code generated by tool 
// Customer.cs 
public partial class Customer // : EntityBaseClasses, interfaces, etc 
{ 
    public int ID 
    { 
     get { /* implementation */ } 
     set { /* implementation */ } 
    } 
} 

與其他類似文件的東西,如帳戶或訂單或這種性質的東西。如果您正在編寫希望利用常用ID屬性的代碼,則可以利用partial class中的partial定義第二個類文件,以向這些模型引入通用接口類型。

public interface IIdentifiableEntity 
{ 
    int ID { get; } 
} 

這裏的美妙之處在於使用它是容易的,因爲實現已經在你生成的模型存在。你只需要聲明它,並且你可以在另一個文件中聲明它。

public partial class Customer : IIdentifiableEntity { } 
public partial class Account : IIdentifiableEntity { } 
// etc. 

這種方法已使用Repository模式時,並希望定義一個通用GetById方法,而不必重複相同的樣板在庫庫後,證明我的價值。我可以將方法/類限制到界面,並獲得「免費」GetById

相關問題