'T' does not contain a definition

Actually it is possible if you know for sure that the generic T has the exact property, using the where (generic type constraint) for a specified class with where T : MyClass.


For instance, if you have two entities Foo and 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;}
}

With a little refactor we can create a BaseClass that will hold the common properties:

class BaseModel
{
    public Guid Id {get; set;}
    public DateTime CreateDate {get; set;}        
}

And modify Foo and Boo to be:

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

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

And If you have a generic service with the constraint type of where T : BaseModel the compiler will allow you to get or set the BaseModel's properties.

Lets say that you want that for every entity (Foo or Boo) added to DB you will want to set the CreateDate and Id properties from code (and not from server default value):

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

If you can't get make an interface for your type (or a common one between several types):

private void GetGenericTableContant<T>(ref StringBuilder outputTableContent, T item, Func<T, string> lineNumberAccessor)
{
     outputTableContent.Append("<td>" + lineNumberAccessor(item) + "</td>");
}

Usage:

GetGenericTableContent(ref outputTableContent, item, x => x.SpreadsheetLineNumbers);

(Or you could just pass the SpreadSheetLineNumbers property if you don't really need the item reference in your method: void GetGenericTableContant<T>(ref StringBuilder outputTableContent, string lineNumbers))


No. Generic types must be known at compile time. Think about it for a minute, how could compiler know that it is guaranteed that type T has property SpreadsheetLineNumbers? What if T is of primitive type such as int or object ?

What prevents us from calling the method like this: GetGenericTableContent(ref _, 999) with T as int here ?

To fix it you could first add an interface that contains the property :

public interface MyInterface 
{
    string SpreadsheetLineNumbers { get; set; }
}

And let your class inherit from this interface:

public class MyClass : MyInterface
{
    public string SpreadsheetLineNumbers { get; set; }
}

Then we use generic type constraints to let compiler know that the type T derives from this interface and therefore it has to contain and implement all its members:

private void GetGenericTableContent<T>(ref StringBuilder outputTableContent, T item) 
    where T : IMyInterface // now compiler knows that type T has implemented SpreadsheetLineNumbers
{
    outputTableContent.Append("<td>" + item.SpreadsheetLineNumbers + "</td>");
}

Tags:

C#

Generics