Reputation: 52942
Is this possible?
var cats = catsource.Select(c => new
{
CatId = c.catId,
Name = c.Name,
}).ToList();
var myCatObject = new CatData(cats);
This doesn't work because the compiler says it can't convert cats
into List<T>
.
cats
is an anonymous type, and CatData
is:
public class CatData<T>
{
public int total;
public int records;
public List<T> records;
public CatData(List<T> dataObjects, int totalRecords, int numberOfRows)
{
total = (int)Math.Ceiling((double)totalRecords / numberOfRows);
records = totalRecords;
rows = dataObjects;
}
}
Any ideas?
Edit:
So I have done this code, but there is still a problem:
public class CatData
{
public int total;
public int records;
public List<T> rows;
private CatData(List<T> dataObjects, int totalRecords, int numberOfRows)
{
total = (int)Math.Ceiling((double)totalRecords / numberOfRows);
records = totalRecords;
rows = dataObjects;
}
public static CatData<T> Create(List<T> dataObjects, int totalRecords, int numberOfRows)
{
return new CatData<T>(dataObjects, totalRecords, numberOfRows);
}
}
This code has an error on every instance of <T>
saying
Cannot resolve symbol T
If I alter the class to be public class CatData<T>
it compiles, but then I cannot have this code:
CatData.Create(records, totalRecords, rows);
Because it says
incorrect number of type parameters.
Update to explain what I want:
I want to create a list of objects which have an anonymous type
var someList = someCollection.Select(new { ... });
I want to create an object which stores them as a List<anonymous>
var myObject = new myObject(someList, 5);
So I can do:
myObject.someValue; // 5 (stored it in the constructor)
myObject.myList.Count(); // can count how many anonymous objects are in there
Perhaps I should just store it as a List<object>
.
I don't really get it, maybe I'm just a bit too thick. I've just ended up with this:
public CatData(List<object> dataObjects, int totalRecords, int numberOfRows)
as my constructor.
var catData = new CatData(records.Cast<object>().ToList(), totalRecords, rows);
Upvotes: 3
Views: 1574
Reputation: 391336
You need to define a factory method.
Generics are inferred (if possible) when calling methods, but not when calling constructors.
So add this:
public static class CatData
{
public static CatData<T> Create<T>(List<T> cats)
{
return new CatData<T>(cats);
}
}
used like this:
var data = CatData.Create(cats);
Eric Lippert has also provided an answer here talking about some of the considerations for why this is not allowed.
With the introduction of the new Roslyn compiler, new features might have a better chance of appearing as it would mean that 1 change can apply to multiple languages and would be easier to implement, which is probably what sparked new life into this discussion, as apparently supporting type inference on generic constructor parameters is now being considered: DamienG's blog, Probable C# 6.0 features illustrated
Since there seems to be some confusion as whether this trick actually works or not, here's a complete LINQPad program that demonstrates:
void Main()
{
var test = new[]
{
new { name = "Test", id = 42 },
new { name = "Test 2", id = 17 }
}.ToList();
CatData.Create(test);
}
public class CatData<T>
{
public CatData(List<T> list)
{
}
}
public static class CatData
{
public static CatData<T> Create<T>(List<T> list)
{
return new CatData<T>(list);
}
}
This works just fine, illustrating that it is entirely legal to have both the static non-generic class and the generic class with the same class name, in the same namespace and assembly.
There should be ample evidence of this in the .NET framework as well, since Tuple exists with multiple versions.
Upvotes: 11
Reputation: 2373
You cannot make a constructor generic; and to instantiate a generic class you need to specify the class parameters.
But, there's a work-around:
public static class CatDataHelper
{
public static CatData<T> MakeCatData<T>(this List<T> list)
{
return new CatData<T>(list);
}
}
//...
var myCatObject = cats.MakeCatData();
Upvotes: 0
Reputation: 125630
Generic type inference works when you call methods, so you should create a factory method:
public static class CatData
{
public static CatData<T> Create<T>(List<T> dataObjects, int totalRecords, int numberOfRows)
{
return new CatData<T>(dataObjects, totalRecords, numberOfRows);
}
}
and now you can do:
var cats = catsource.Select(c => new
{
CatId = c.catId,
Name = c.Name,
}).ToList();
var myCatObject = CatData.Create(cats, cats.Length, cats.Length);
Upvotes: 2
Reputation: 277
Instead of using var use dynamic.
dynamic cats = catsource.Select(c => new
{
CatId = c.catId,
Name = c.Name,
}).ToList();
Upvotes: -4