'T'不包含定义

时间:2016-09-23 11:00:58

标签: c# generics

是否可以执行以下操作(如果是这样,我似乎无法使其工作..暂时放弃约束)...

如果推断出类型(因为它已被省略),那么问题是什么?

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指令或汇编引用?)

3 个答案:

答案 0 :(得分:18)

不,这是不可能的。必须在编译时知道泛型类型。 考虑一下,编译器如何知道类型T具有SpreadsheetLineNumbers属性?如果T是基本类型,例如intobject

,该怎么办?

什么阻止我们用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具有确切的属性。


例如,如果您有两个实体FooBoo

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;}        
}

并将FooBoo修改为:

class Boo : BaseModel
{
    public int BooProp {get; set;}
}

class Foo : BaseModel
{
    public int FooProp {get; set;}
}

如果您有一个约束类型为where T : BaseModel的通用服务,编译器将允许您获取或设置BaseModel的属性。

让我们说,您希望对于添加到数据库中的每个实体(FooBoo),都需要从代码中设置CreateDateId属性(以及不是来自服务器默认值):

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);           
    } 
}