我有一些具有公共属性的类,但是,我不能使它们从基类型派生(LINQ-to-SQL限制)。
我想将它们视为具有基本类型,但不使用反射(性能至关重要)。
例如:
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
但是,我正在寻找一种方法来限制代码在编译时中使用此方法来处理没有{{ 1}}属性。
答案 0 :(得分: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;
}
但是,如果您无法修改类以添加界面,则无法执行此操作。没有编译时检查将验证T
上是否存在属性。你必须使用反射 - 这很慢,显然不理想。
答案 1 :(得分: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;
}
答案 2 :(得分: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);
答案 3 :(得分:1)
提到接口方法的其他答案肯定是好的,但我想针对涉及Linq-to-SQL的情况定制响应。
但首先,要解决问题标题
可以在没有基类型的情况下使用C#约束吗?
一般来说,答案是否定的。具体来说,您可以使用struct
,class
或new()
作为约束,这些不是技术上的基本类型,并且它们确实提供了有关如何使用类型的一些指导。这并没有达到你想要做的水平,即将方法限制为具有特定属性的类型。为此,您需要约束到特定的接口或基类。
对于您的特定用例,您提到了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
中的partial class
来定义第二个类文件以引入这些模型的通用接口类型。
public interface IIdentifiableEntity
{
int ID { get; }
}
这里的美妙之处在于使用它很容易,因为实现已经存在于生成的模型中。你只需要声明它,你就可以在另一个文件中声明它。
public partial class Customer : IIdentifiableEntity { }
public partial class Account : IIdentifiableEntity { }
// etc.
这种方法对我来说在使用存储库模式时非常有价值,并且希望定义一般的GetById
方法,而不必在存储库之后重复存储库中的相同样板。我可以将方法/类约束到接口,并获取GetById
为“free”。
答案 4 :(得分:0)
您需要使两个类都实现具有所需属性的接口,并在泛型约束中使用它,或者为每种类型编写单独的方法。这是你获得编译时安全的唯一方法。