Reputation: 8372
I have a Generic class,DisplayGrid
...
class DisplayGrid<T> where T : class
... which has a List
of <T>
as a property.
public List<T> allRows;
... within a property of DisplayGrid
I want to iterate over allRows
and access a method of <T>
...
foreach (T r in this.allRows)
{
if (!(r.isAValidRow))
{
blnRowsValid = false;
break;
}
}
... however attempting to make use of the isAValidRow
method defined on <T>
generates a compiler error ...
error CS1061: 'T' does not contain a definition for 'isAValidRow' and no extension method 'isAValidRow' accepting a first argument of type 'T' could be found
Reading back through old questions it seems this area has changed over the years. It seems unlikely that such a basic requirement would still be impossible ?
EDIT 1 : In the original version of this question I perhaps went too far in trying to simplify the sample code. I only included a single Row
class but what I meant to imply is that there were multiple classes which might be used as a 'Row' when instantiating the DisplayGrid
class.
I have now adapted the classes below so that there are two different classes which might be used as the <T>
of the DisplayGrid
class.
In doing this I hope to address a number of comments which, correctly, suggested there wasn't any need to use Generics, or that the 'where' directive could be limited to the only class, Row
, which I had supplied in the example.
In the changes to the example I have defined classes RowA
and RowB
and I do appreciate that as shown they are functionally identical but this is just to make a simple example - in actual use RowA
and RowB
would be sufficiently distinctive to justify their not being the same class.
All Both classes referenced above appear below :
class DisplayGrid<T> where T : class
{
public List<T> allRows;
public DisplayGrid()
{
this.allRows = new List<T>();
}
public bool hasRowMsgs
{
get
{
bool blnRowsValid = true;
foreach (T r in this.allRows)
{
if (!(r.isAValidRow))
{
blnRowsValid = false;
break;
}
}
return blnRowsValid;
}
}
public bool isAValidTable
{
get {
if (this.hasRowMsgs == false)
{
return true;
}
else
{
return false;
}
}
}
}
class RowA
{
public List<string> rowMsgs;
public RowA()
{
rowMsgs = new List<string>();
}
public bool isAValidRow
{
get {
return (this.rowMsgs.Count == 0) ? true : false;
}
}
}
class RowB
{
public List<string> rowMsgs;
public RowB()
{
rowMsgs = new List<string>();
}
public bool isAValidRow
{
get {
return (this.rowMsgs.Count == 0) ? true : false;
}
}
}
Upvotes: 0
Views: 96
Reputation: 8372
After having read, and understood the significance of, the comment by Lee I now have a working version. The key to making it work was defining an Interface, IRow
and applying it to the 'Row' classes, RowA
and RowB
.
For the sake of future readers here are the classes which now work.
Two points
RowA
and RowB
are unrealistically similar, this is only to allow the issue to be illustrated simply and briefly, clearly in a real implementation they would be less similar.
class DisplayGrid<T> where T : IRow
{
public List<T> allRows;
public DisplayGrid()
{
this.allRows = new List<T>();
}
public bool hasRowMsgs
{
get
{
bool blnHasRowMsgs = false;
foreach (T r in this.allRows)
{
if (!(r.isAValidRow))
{
blnHasRowMsgs = true;
break;
}
}
return blnHasRowMsgs;
}
}
public bool isAValidTable
{
get {
return (!(this.hasRowMsgs));
}
}
}
interface IRow
{
bool isAValidRow { get; }
}
public class RowA : IRow
{
public List<string> rowMsgs;
public bool isAValidRow {
get {
return this.rowMsgs.Count > 0 ? false : true;
}
}
public RowA()
{
rowMsgs = new List<string>();
}
}
public class RowB : IRow
{
public List<string> rowMsgs;
public bool isAValidRow {
get {
return this.rowMsgs.Count > 0 ? false : true;
}
}
public RowB()
{
rowMsgs = new List<string>();
}
}
Upvotes: 2
Reputation: 53
If you change the first line to
class DisplayGrid<T> where T : Row
then it should work.
Explanation: The method you are trying to use is a property of a Row; it is not a method of 'class' so it is not recognized.
Upvotes: 0