是否可以执行以下操作(如果是这样,我似乎无法使其工作..暂时放弃约束)...
如果推断出类型(因为它已被省略),那么问题是什么?
private void GetGenericTableContent<T>(ref StringBuilder outputTableContent, T item)
{
outputTableContent.Append("<td>" + item.SpreadsheetLineNumbers + "</td>");
}
// 'item' is either DuplicateSpreadsheetRowModel class or SpreadsheetRowModel class
使用上面的代码我收到以下错误:
'T'不包含'SpreadsheetLineNumbers'的定义,并且没有扩展方法'SpreadsheetLineNumbers'可以找到接受类型'T'的第一个参数(你是否缺少using指令或汇编引用?)
答案 0 :(得分:18)
不,这是不可能的。必须在编译时知道泛型类型。
考虑一下,编译器如何知道类型T
具有SpreadsheetLineNumbers
属性?如果T
是基本类型,例如int
或object
?
什么阻止我们用ref _, 999
参数调用方法(T在这里是int)?
仅当我们添加包含此属性的接口时才会起作用:
public interface MyInterface
{
string SpreadsheetLineNumbers { get; set; }
}
让你的类从这个接口继承
public class MyClass : MyInterface
{
public string SpreadsheetLineNumbers { get; set; }
}
然后使用泛型约束让编译器知道此类型是从此接口继承的,因此必须包含其所有属性。
private void GetGenericTableContent<T>(ref StringBuilder outputTableContent, T item)
where T : IMyInterface // now compiler knows that T type has implemented all members of the interface
{
outputTableContent.Append("<td>" + item.SpreadsheetLineNumbers + "</td>");
}
答案 1 :(得分:5)
如果你不能为你的类型(或几种类型之间的通用)创建一个接口:
private void GetGenericTableContant<T>(ref StringBuilder outputTableContent, T item, Func<T, string> lineNumberAccessor)
{
outputTableContent.Append("<td>" + lineNumberAccessor(item) + "</td>");
}
用法:
GetGenericTableContent(ref outputTableContent, item, x => x.SpreadsheetLineNumbers);
(或者如果你真的不需要方法中的项目参考,你可以传递SpreadSheetLineNumbers属性:void GetGenericTableContant<T>(ref StringBuilder outputTableContent, string lineNumbers)
)
答案 2 :(得分:0)
实际上,如果您确定确定,则可以对where T : MyClass
的指定类使用where(通用类型约束)来确定通用T具有确切的属性。
例如,如果您有两个实体Foo
和Boo
:
class Foo
{
public Guid Id {get; set;}
public DateTime CreateDate {get; set;}
public int FooProp {get; set;}
}
class Boo
{
public Guid Id {get; set;}
public DateTime CreateDate {get; set;}
public int BooProp {get; set;}
}
只需一点重构,我们就可以创建一个BaseClass
来保存通用属性:
class BaseModel
{
public Guid Id {get; set;}
public DateTime CreateDate {get; set;}
}
并将Foo
和Boo
修改为:
class Boo : BaseModel
{
public int BooProp {get; set;}
}
class Foo : BaseModel
{
public int FooProp {get; set;}
}
如果您有一个约束类型为where T : BaseModel
的通用服务,编译器将允许您获取或设置BaseModel
的属性。
让我们说,您希望对于添加到数据库中的每个实体(Foo
或Boo
),都需要从代码中设置CreateDate
和Id
属性(以及不是来自服务器默认值):
public interface IGenericService<T>
{
void Insert(T obj);
}
public class GenericService<T> : IGenericService<T> where T : BaseModel
{
public void Insert(T obj)
{
obj.Id = Guid.NewGuid();
obj.CreateDate = DateTime.UtcNow;
this._repository.Insert(obj);
}
}