在C#我有这样的情况:
class ModelBase<TKey>
{
TKey Id { get; set; }
}
class Repo<TModel, TKey> :
where TModel : ModelBase<TKey>
{
//code where I access both TModel and TKey types
}
在我的Repo类中,我需要同时访问TModel
和TKey
,但是当我特定TModel
参数时,模式匹配系统应该能够提取{{ 1}}自动。
要使用TKey
泛型类型,我必须将其声明为泛型参数,因此每次我需要创建一个Repo时,我必须使用特定的模型和相对键类型。我怎样才能删除显式键类型的需要,并通过模式匹配来提取它?在编译时使用验证的解决方案是首选。
答案 0 :(得分:2)
由于两个原因,您在C#中无法提出要求:
构造函数中没有类型推断:
class Foo<T>
{
public Foo(T t) { ... }
}
var foo = new Foo(1); //compile time error, `int` will not be inferred
这种限制很奇怪,并且与方法类型推断的工作方式完全不一致。构造函数不是方法,但应该
类型推断是全部或全部,没有中间立场:
T Whatever<T, Q>(Q q) where Q: T { ... }
您可能认为的任何假设语法中的部分类型推断根本不起作用:
var blah = NewFoo<Blah>(q); //compile time error
或者
var blah = NewFoo<Blah,>(q); //compile time error
将会失败。
为什么呢?好吧,因为语言是按照它的方式设计的。第一个限制可以解决,第二个限制我不会很快看到它发生,所以如果你打算等待它,请坐下。
答案 1 :(得分:1)
我认为对此的解决方法可能是声明一个非泛型类型,其中包含一个属性来存储主键类型。然后泛型类型可以继承,并在构造函数中设置属性。
这样的事情:
class ModelBase
{
public Type KeyType { get; set; }
}
class ModelBase<TKey> : ModelBase
{
public TKey Id { get; set; }
public ModelBase()
{
KeyType = typeof(TKey);
}
}
class Repo<TModel> where TModel : ModelBase, new()
{
// code where I access both TModel and TKey types
public void Test()
{
var modelType = typeof(TModel).Name;
var keyType = new TModel().KeyType.Name;
Console.WriteLine($"{modelType} {keyType}");
}
}
允许你编写这样的代码:
class MyIntEntity : ModelBase<int>
{
public new int Id { get; set; }
}
class MyStringEntity : ModelBase<string>
{
public new string Id { get; set; }
}
class Program
{
static void Main(string[] args)
{
var repoIntegerKey = new Repo<MyIntEntity>();
var repoStringKey = new Repo<MyStringEntity>();
repoIntegerKey.Test(); // prints "MyIntEntity Int32"
repoStringKey.Test(); // prints "MyStringEntity String"
Console.ReadLine();
}
}