I have a Dictionary:
Dictionary<int, Type> AllDrillTypes = new Dictionary<int, Type>()
{
{13,typeof(TCHEMISTRY)},
{14,typeof(TDRILLSPAN)}
};
where TCHEMISTRY and TDRILLSPAN are classes. Then I want to get rows from one of this classes like this:
Type T = AllDrillTypes[13];
var LC = Activator.CreateInstance( typeof(List<>).MakeGenericType( T ) );
MethodInfo M = T.GetMethod("FindAll", BindingFlags.Public | BindingFlags.Static, null, new Type[] { }, null);
LC = M.Invoke(null, new object[] { });
All this code works correctly. After that I need to get some rows like this:
var LingLC = from obj in LC where obj.RunID == 1001 select obj;
But this line causes error:
"Could not find an implementation of the query pattern for source type
'object'. 'Where' not found."
What's wrong with this code line?
Even if you can't change the class definitions, you can avoid using reflection:
// Getter dictionary rather than type dictionary.
Dictionary<int, Func<IEnumerable<object>>> DrillTypeGetters =
new Dictionary<int, Func<IEnumerable<object>>>()
{
{ 13, () => TCHEMISTRY.FindAll().Cast<object>() },
{ 14, () => TDRILLSPAN.FindAll().Cast<object>() }
};
Dictionary<int, Func<object, int>> IDGetters =
new Dictionary<int, Func<object, int>>()
{
{ 13, o => ((TCHEMISTRY)o).RunID },
{ 14, o => ((TDRILLSPAN)o).RunID }
};
IEnumerable<object> LC = DrillTypeGetters[13]();
IEnumerable<object> LingLC =
from obj in LC
where IDGetters[13](obj) == 1001
select obj;
Or you could even just switch on 13/14 and run a completely different method per type.
if (choice == 13)
IEnumerable<TCHEMISTRY> LingLC =
TCHEMISTRY.FindAll().Where(tc => tc.RunID == 1001);
else if (choice == 14)
IEnumerable<TDRILLSPAN> LingLC =
TDRILLSPAN.FindAll().Where(td => td.RunID == 1001);
Basically, if the two classes don't share any common hierarchy, you can't write any common code to deal with them. If they have lots of similar properties, you can use getters as in my first example to provide a way to get the similar properties whatever type of class you're dealing with. If they don't even have similar properties, don't try to write shared code.
Maybe you could rewrite your code to something like this, .... to get a more type-safe solution (without using reflection).
void Main()
{
var driller1 = new DrillerWhichYouCannotChange1();
var driller2 = new DrillerWhichYouCannotChange2();
var allDrillTypes = new Dictionary<int, IList<IDriller>>()
{
{ 13, new List<IDriller>() { new DrillerWhichYouCannotChange1Adapter(driller1) } },
{ 14, new List<IDriller>() { new DrillerWhichYouCannotChange2Adapter(driller2) } },
};
Console.WriteLine(allDrillTypes[13][0].SomeCommonProperty); // prints 123
Console.WriteLine(allDrillTypes[14][0].SomeCommonProperty); // prints 456
}
interface IDriller
{
int SomeCommonProperty { get; }
}
class DrillerWhichYouCannotChange1Adapter : IDriller
{
private DrillerWhichYouCannotChange1 inner;
public DrillerWhichYouCannotChange1Adapter(DrillerWhichYouCannotChange1 inner)
{
this.inner = inner;
}
public int SomeCommonProperty { get { return this.inner.PropertyX; } }
}
class DrillerWhichYouCannotChange2Adapter : IDriller
{
private DrillerWhichYouCannotChange2 inner;
public DrillerWhichYouCannotChange2Adapter(DrillerWhichYouCannotChange2 inner)
{
this.inner = inner;
}
public int SomeCommonProperty { get { return this.inner.PropertyY; } }
}
class DrillerWhichYouCannotChange1
{
public int PropertyX { get { return 123; } }
}
class DrillerWhichYouCannotChange2
{
public int PropertyY { get { return 456; } }
}
EDIT: If you cannot change the driller classes, you could use the adapter-pattern to create one adapter per driller, which implements IDiller.
you need to cast LC to the to the return type of the FindAll method. Something on the lines of:
var genericList = ((List<TChemistry>) LC);
var LingLC = from obj in genericList where obj.RunID == 1001 select obj;
This is assuming that FindAll returns a collection of TChemistry.
--edit
If you do not know at runtime if the type will be TChemistry or TDrillspan, then you will have to write an if/else of switch statement to cast to the correct type. I would rather have TChemistry and TDrillSpan extend an abstract class or an interface, and you can just cast to List, and you will always have RunId property.
public abstract class TAbstract
{
public abstract int RunId {get; set;}
}
public class TChemistry : TAbstract
{
public override int RunId {get; set;}
}
public class TDrillSpan : TAbstract
{
public override int RunId {get; set;}
}
Type T = AllDrillTypes[13] as TAbstract;
var LC = Activator.CreateInstance( typeof(List<>).MakeGenericType( T ) );
MethodInfo M = T.GetMethod("FindAll", BindingFlags.Public | BindingFlags.Static, null, new Type[] { }, null);
LC = M.Invoke(null, new object[] { });
var genericList = ((List<TAbstract>) LC);
var LingLC = from obj in genericList where obj.RunID == 1001 select obj;
If you cannot change the declaration of classes, then you are only left with ugly if else:
var typeInfo = LC.GetType();
IEnumerable<T> genericList;
if (typeInfo == typeof(IEnumerable<TChemistry>)
{
genericList = (List<TChemistry>) LC;
)
else if (typeInfo == typeof(IEnumerable<TDrillSpan>)
{
genericList = (List<TDrillSpan>) LC;
}
var LingLC = from obj in genericList where obj.RunID == 1001 select obj;
try
IEnumerable returnedObjects = (IEnumerable)M.Invoke(null, new object[] { }) as IEnumerable;
then iterate through your ienumerable
foreach (object report in returnedObjects)
{
// Use reflection to read properties or add to a new List<object> if you
// need an ICollection<object>
}
instead of :
LC = M.Invoke(null, new object[] { });
Related
I simply want to do this:
(inputObj ) => (inputObj .Select(objEln=> hubObjectConverter(objEln)));
inputObj ----> List<elnObject>
hubObjectConverter ----> Func<object,object>
Where am I going wrong?
var typeElnObjList = typeof(List<>).MakeGenericType(new[] { elnObjectType });
var inputObj = Expression.Parameter(typeElnObjList, "lstElnObj");
var paramSelectMeth = Expression.Parameter(elnObjectType, "objEln");
var convertToObject = Expression.Invoke(Expression.Constant(hubObjectConverter), paramSelectMeth);
var lambdaSelect = Expression.Lambda(convertToObject, paramSelectMeth);
var convertList = Expression.Call(typeof(Enumerable),
"Select",
new[] { elnObjectType, hubObjectType },
inputObj,
lambdaSelect); <------ I keep getting an error here. Saying Select cannot accept generic type. Where am I going wrong?
(I assume your question is an X/Y problem, so I won't answer your question at face-value)
If your intent is to allow converting from a List<TIn> to a List<TOut> by specifying the type of TOut at runtime with a Type rather than a generic-type parameter then you only need MakeGenericMethod and you don't need to use Expression<> at all:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public static class ListExtensions
{
public static IList ConvertList<TSource>( this List<TSource> source, Type destinationType, Func<object,object> hubObjectConverter )
{
if( source is null ) throw new ArgumentNullException(nameof(source));
if( destinationType is null ) throw new ArgumentNullException(nameof(destinationType));
//
MethodInfo mi = typeof(ListExtensions)
.GetMethod( nameof(ConvertListImpl), BindingFlags.Static | BindingFlags.NonPublic )
.MakeGenericMethod( typeof(TSource), destinationType );
Object result = mi.Invoke( obj: null, new Object[] { source, hubObjectConverter } );
return (IList)result;
}
private static List<TOut> ConvertListImpl<TIn,TOut>( List<TIn> source, Func<Object,Object> converter )
{
return source
.Select( item => converter( item ) )
.Cast<TOut>()
.ToList();
}
}
(To improve performance, the MethodInfo could be cached in a static readonly ConcurrentDictionary<(TIn,TOut),MethodInfo> dictionary).
It would be used like so:
List<Int32> listOfInt32 = new List<Int32>() { 1, 2, 3, 4, 5 };
IList listOfString = listOfInt32.ConvertList( destinationType: typeof(String), obj => obj.ToString() );
Even though listOfString is statically-typed as IList, its actual runtime type is List<String>.
If do know source type ,That is anonymous type . So convert that to object type
class Address
{
public string Street { get; set; }
public Foo Foo { get; set; }
}
class User
{
public string Name { get; set; }
public Address Address { get; set; }
}
public static List<object> ConvertToListOfObjects<T>(List<T> list)
{
return list.ConvertAll<object>(t => t);
}
static void Converttotarget()
{
User testUser = new User()
{
Name = "Paul",
Address = new Address()
{
Street = "Freeway",
Foo = new Foo() { Bar = "Baz" }
}
};
var users = new List<User>();
users.Add(testUser);
var objusers = ConvertToListOfObjects(users);
var testbj = new { name = "test", rol = 1 };
var objelist = new List<object>();
objelist.Add(testbj);
var lst = ConvertToListOfObjects(objelist);
}
Storing the generic class T in a variable and reusing it in sub methode.
For a WebService with crud on few object:
Foo: Bar: Etc..
SetFoo SetBar SetEtc
GetFoo GetBar GetEtc
UpdateFoo UpdateBar UpdateEtc
DeleteFoo DeleteBar DeleteEtc
GetList .. ..
GetPending .. ..
Processed .. ..
I have the following singleton generic wrapper on client side, with methode like:
public bool Get<T>(int i, out DloExtention result)
// DloExtention is an interface implemented by foo, bar, etc..
{
result = null;
try
{
if (typeof(T) == typeof(Foo))
{
result = WebserviceClient.GetFoo(i);
}
else if (typeof(T) == typeof(Bar))
{
result = WebserviceClient.GetBar(i);
}
else if (typeof(T) == typeof(Etc))
{
result = WebserviceClient.GetEtc(i);
}
else
{
throw new NotSupportedException("Get<T>, T is not a supported type.");
}
}
catch (Exception ex)
{
Log4N.Logger.Error($"Error in Namespace.ClientSide.Get<{nameof(T)}>(int {i} ). " + ex.Message);
return false;
}
return true;
}
So I can handle all the type simply with the same generic object:
class Processor
{
HashSet<int> validOperation = new HashSet<int>();
HashSet<int> invalidOperation = new HashSet<int>();
internal void Run<T>()
{
if (Wrapper.Instance.GetListPending<T>(out int[] newEntityList) && newEntityList.Any())
{
ProcessEntities<T>(newEntityList, false);
}
}
private void ProcessEntities<T>(int[] idsEnt, bool singleMode)
{
foreach (var idEnt in idsEnt)
{
ProcessEntity<T>(idEnt, false);
}
CloseValidOperation();
RemoveInvalidOperation();
}
internal void ProcessIncident<T>(int idEnt)
{
if (Wrapper.Instance.Get<T>(idEnt, out LanDataExchangeCore.LanDataExchangeWCF.DloExtention currentEntity))
{
if (currentEntity.isValid() && currentEntity.toLocalDB())
{
validOperation.Add(idEnt);
}
else
{
invalidOperation.Add(idEnt);
}
}
}
Only Wrapper.Instance.Get<T> and Wrapper.Instance.GetListPending<T> needs the generic parameter.
But every methode in the way need to use it only to be able to deliver <T> to the last methode.
Is there a way to save the <T> in the Run<T> call into a private variable so inner methode of the class can use it ?
I have try adding a Type myType; but can't find the way to use it in generic call. Exemple for the Wrapper.Instance.Get<T>
Type myType; // class property
var fooWrapperGet = typeof(Wrapper).GetMethod("Get");
var fooOfMyTypeMethod = fooWrapperGet.MakeGenericMethod(new[] { myType });
//fooOfMyTypeMethod.Invoke(Wrapper.Instance , new object[] { new myType() });
// fooWrapperGet, as my wrapper is a singleton, Wrapper dont exposed Get<T>, but Wrapper.instance will expose it.
// new myType() <- do not compile.
Does this work for you?
private Dictionary<Type, Func<int, DloExtention>> gets =
new Dictionary<System.Type, Func<int, DloExtention>>()
{
{ typeof(Foo), WebserviceClient.GetFoo },
{ typeof(Bar), WebserviceClient.GetBar },
{ typeof(Etc), WebserviceClient.GetEtc },
};
public bool Get<T>(int i, out DloExtention result)
{
result = null;
var flag = false;
if (gets.ContainsKey(typeof(T)))
{
result = gets[typeof(T)](i);
flag = true;
}
return flag;
}
The beauty of this is that you can populate your dictionary at run-time.
I want to get the names of all properties that changed for matching objects. I have these (simplified) classes:
public enum PersonType { Student, Professor, Employee }
class Person {
public string Name { get; set; }
public PersonType Type { get; set; }
}
class Student : Person {
public string MatriculationNumber { get; set; }
}
class Subject {
public string Name { get; set; }
public int WeeklyHours { get; set; }
}
class Professor : Person {
public List<Subject> Subjects { get; set; }
}
Now I want to get the objects where the Property values differ:
List<Person> oldPersonList = ...
List<Person> newPersonList = ...
List<Difference> = GetDifferences(oldPersonList, newPersonList);
public List<Difference> GetDifferences(List<Person> oldP, List<Person> newP) {
//how to check the properties without casting and checking
//for each type and individual property??
//can this be done with Reflection even in Lists??
}
In the end I would like to have a list of Differences like this:
class Difference {
public List<string> ChangedProperties { get; set; }
public Person NewPerson { get; set; }
public Person OldPerson { get; set; }
}
The ChangedProperties should contain the name of the changed properties.
I've spent quite a while trying to write a faster reflection-based solution using typed delegates. But eventually I gave up and switched to Marc Gravell's Fast-Member library to achieve higher performance than with normal reflection.
Code:
internal class PropertyComparer
{
public static IEnumerable<Difference<T>> GetDifferences<T>(PropertyComparer pc,
IEnumerable<T> oldPersons,
IEnumerable<T> newPersons)
where T : Person
{
Dictionary<string, T> newPersonMap = newPersons.ToDictionary(p => p.Name, p => p);
foreach (T op in oldPersons)
{
// match items from the two lists by the 'Name' property
if (newPersonMap.ContainsKey(op.Name))
{
T np = newPersonMap[op.Name];
Difference<T> diff = pc.SearchDifferences(op, np);
if (diff != null)
{
yield return diff;
}
}
}
}
private Difference<T> SearchDifferences<T>(T obj1, T obj2)
{
CacheObject(obj1);
CacheObject(obj2);
return SimpleSearch(obj1, obj2);
}
private Difference<T> SimpleSearch<T>(T obj1, T obj2)
{
Difference<T> diff = new Difference<T>
{
ChangedProperties = new List<string>(),
OldPerson = obj1,
NewPerson = obj2
};
ObjectAccessor obj1Getter = ObjectAccessor.Create(obj1);
ObjectAccessor obj2Getter = ObjectAccessor.Create(obj2);
var propertyList = _propertyCache[obj1.GetType()];
// find the common properties if types differ
if (obj1.GetType() != obj2.GetType())
{
propertyList = propertyList.Intersect(_propertyCache[obj2.GetType()]).ToList();
}
foreach (string propName in propertyList)
{
// fetch the property value via the ObjectAccessor
if (!obj1Getter[propName].Equals(obj2Getter[propName]))
{
diff.ChangedProperties.Add(propName);
}
}
return diff.ChangedProperties.Count > 0 ? diff : null;
}
// cache for the expensive reflections calls
private Dictionary<Type, List<string>> _propertyCache = new Dictionary<Type, List<string>>();
private void CacheObject<T>(T obj)
{
if (!_propertyCache.ContainsKey(obj.GetType()))
{
_propertyCache[obj.GetType()] = new List<string>();
_propertyCache[obj.GetType()].AddRange(obj.GetType().GetProperties().Select(pi => pi.Name));
}
}
}
Usage:
PropertyComparer pc = new PropertyComparer();
var diffs = PropertyComparer.GetDifferences(pc, oldPersonList, newPersonList).ToList();
Performance:
My very biased measurements showed that this approach is about 4-6 times faster than the Json-Conversion and about 9 times faster than ordinary reflections. But in fairness, you could probably speed up the other solutions quite a bit.
Limitations:
At the moment my solution doesn't recurse over nested lists, for example it doesn't compare individual Subject items - it only detects that the subjects lists are different, but not what or where. However, it shouldn't be too hard to add this feature when you need it. The most difficult part would probably be to decide how to represent these differences in the Difference class.
We start with 2 simple methods:
public bool AreEqual(object leftValue, object rightValue)
{
var left = JsonConvert.SerializeObject(leftValue);
var right = JsonConvert.SerializeObject(rightValue);
return left == right;
}
public Difference<T> GetDifference<T>(T newItem, T oldItem)
{
var properties = typeof(T).GetProperties();
var propertyValues = properties
.Select(p => new {
p.Name,
LeftValue = p.GetValue(newItem),
RightValue = p.GetValue(oldItem)
});
var differences = propertyValues
.Where(p => !AreEqual(p.LeftValue, p.RightValue))
.Select(p => p.Name)
.ToList();
return new Difference<T>
{
ChangedProperties = differences,
NewItem = newItem,
OldItem = oldItem
};
}
AreEqual just compares the serialized versions of two objects using Json.Net, this keeps it from treating reference types and value types differently.
GetDifference checks the properties on the passed in objects and compares them individually.
To get a list of differences:
var oldPersonList = new List<Person> {
new Person { Name = "Bill" },
new Person { Name = "Bob" }
};
var newPersonList = new List<Person> {
new Person { Name = "Bill" },
new Person { Name = "Bobby" }
};
var diffList = oldPersonList.Zip(newPersonList, GetDifference)
.Where(d => d.ChangedProperties.Any())
.ToList();
Everyone always tries to get fancy and write these overly generic ways of extracting data. There is a cost to that.
Why not be old school simple.
Have a GetDifferences member function Person.
virtual List<String> GetDifferences(Person otherPerson){
var diffs = new List<string>();
if(this.X != otherPerson.X) diffs.add("X");
....
}
In inherited classes. Override and add their specific properties. AddRange the base function.
KISS - Keep it simple. It would take you 10 minutes of monkey work to write it, and you know it will be efficient and work.
I am doing it by using this:
//This structure represents the comparison of one member of an object to the corresponding member of another object.
public struct MemberComparison
{
public static PropertyInfo NullProperty = null; //used for ROOT properties - i dont know their name only that they are changed
public readonly MemberInfo Member; //Which member this Comparison compares
public readonly object Value1, Value2;//The values of each object's respective member
public MemberComparison(PropertyInfo member, object value1, object value2)
{
Member = member;
Value1 = value1;
Value2 = value2;
}
public override string ToString()
{
return Member.name+ ": " + Value1.ToString() + (Value1.Equals(Value2) ? " == " : " != ") + Value2.ToString();
}
}
//This method can be used to get a list of MemberComparison values that represent the fields and/or properties that differ between the two objects.
public static List<MemberComparison> ReflectiveCompare<T>(T x, T y)
{
List<MemberComparison> list = new List<MemberComparison>();//The list to be returned
if (x.GetType().IsArray)
{
Array xArray = x as Array;
Array yArray = y as Array;
if (xArray.Length != yArray.Length)
list.Add(new MemberComparison(MemberComparison.NullProperty, "array", "array"));
else
{
for (int i = 0; i < xArray.Length; i++)
{
var compare = ReflectiveCompare(xArray.GetValue(i), yArray.GetValue(i));
if (compare.Count > 0)
list.AddRange(compare);
}
}
}
else
{
foreach (PropertyInfo m in x.GetType().GetProperties())
//Only look at fields and properties.
//This could be changed to include methods, but you'd have to get values to pass to the methods you want to compare
if (!m.PropertyType.IsArray && (m.PropertyType == typeof(String) || m.PropertyType == typeof(double) || m.PropertyType == typeof(int) || m.PropertyType == typeof(uint) || m.PropertyType == typeof(float)))
{
var xValue = m.GetValue(x, null);
var yValue = m.GetValue(y, null);
if (!object.Equals(yValue, xValue))//Add a new comparison to the list if the value of the member defined on 'x' isn't equal to the value of the member defined on 'y'.
list.Add(new MemberComparison(m, yValue, xValue));
}
else if (m.PropertyType.IsArray)
{
Array xArray = m.GetValue(x, null) as Array;
Array yArray = m.GetValue(y, null) as Array;
if (xArray.Length != yArray.Length)
list.Add(new MemberComparison(m, "array", "array"));
else
{
for (int i = 0; i < xArray.Length; i++)
{
var compare = ReflectiveCompare(xArray.GetValue(i), yArray.GetValue(i));
if (compare.Count > 0)
list.AddRange(compare);
}
}
}
else if (m.PropertyType.IsClass)
{
var xValue = m.GetValue(x, null);
var yValue = m.GetValue(y, null);
if ((xValue == null || yValue == null) && !(yValue == null && xValue == null))
list.Add(new MemberComparison(m, xValue, yValue));
else if (!(xValue == null || yValue == null))
{
var compare = ReflectiveCompare(m.GetValue(x, null), m.GetValue(y, null));
if (compare.Count > 0)
list.AddRange(compare);
}
}
}
return list;
}
Here you have a code which does what you want with Reflection.
public List<Difference> GetDifferences(List<Person> oldP, List<Person> newP)
{
List<Difference> allDiffs = new List<Difference>();
foreach (Person oldPerson in oldP)
{
foreach (Person newPerson in newP)
{
Difference curDiff = GetDifferencesTwoPersons(oldPerson, newPerson);
allDiffs.Add(curDiff);
}
}
return allDiffs;
}
private Difference GetDifferencesTwoPersons(Person OldPerson, Person NewPerson)
{
MemberInfo[] members = typeof(Person).GetMembers();
Difference returnDiff = new Difference();
returnDiff.NewPerson = NewPerson;
returnDiff.OldPerson = OldPerson;
returnDiff.ChangedProperties = new List<string>();
foreach (MemberInfo member in members)
{
if (member.MemberType == MemberTypes.Property)
{
if (typeof(Person).GetProperty(member.Name).GetValue(NewPerson, null).ToString() != typeof(Person).GetProperty(member.Name).GetValue(OldPerson, null).ToString())
{
returnDiff.ChangedProperties.Add(member.Name);
}
}
}
return returnDiff;
}
How can I set generic type dynamically?
public class A
{
public int X { get; set; }
public A()
{
X = 9000;
}
}
public class Class1
{
public void Test()
{
List<A> theList = new List<A>() {
new A { X = 1 },
new A { X = 2 }
};
object testObj = theList;
var argType = testObj.GetType().GetGenericArguments()[0];
Foo(testObj as ICollection<argType>); // ?
}
public void Foo<T>(ICollection<T> items) where T:new()
{
T newItem = new T();
items.Add(newItem);
}
To do in "regular" c# you would use reflection to obtain the MethodInfo, then use MakeGenericMethod() and Invoke(). However, this is easier:
Foo((dynamic)testObj);
The reflection approach here is:
var method = typeof(Class1).GetMethod("Foo").MakeGenericMethod(argType);
method.Invoke(this, new object[] { testObj });
You can't do that, because in the Foo function you are supposed to do something with the collection, and there's no guarantee that the type will be safe.
The only way is using an "object" then casting to the proper type within the Fooo function.
If BaseFruit has a constructor that accepts an int weight, can I instantiate a piece of fruit in a generic method like this?
public void AddFruit<T>()where T: BaseFruit{
BaseFruit fruit = new T(weight); /*new Apple(150);*/
fruit.Enlist(fruitManager);
}
An example is added behind comments. It seems I can only do this if I give BaseFruit a parameterless constructor and then fill in everything through member variables. In my real code (not about fruit) this is rather impractical.
-Update-
So it seems it can't be solved by constraints in any way then. From the answers there are three candidate solutions:
Factory Pattern
Reflection
Activator
I tend to think reflection is the least clean one, but I can't decide between the other two.
Additionally a simpler example:
return (T)Activator.CreateInstance(typeof(T), new object[] { weight });
Note that using the new() constraint on T is only to make the compiler check for a public parameterless constructor at compile time, the actual code used to create the type is the Activator class.
You will need to ensure yourself regarding the specific constructor existing, and this kind of requirement may be a code smell (or rather something you should just try to avoid in the current version on c#).
You can't use any parameterised constructor. You can use a parameterless constructor if you have a "where T : new()" constraint.
It's a pain, but such is life :(
This is one of the things I'd like to address with "static interfaces". You'd then be able to constrain T to include static methods, operators and constructors, and then call them.
Yes; change your where to be:
where T:BaseFruit, new()
However, this only works with parameterless constructors. You'll have to have some other means of setting your property (setting the property itself or something similar).
Most simple solution
Activator.CreateInstance<T>()
As Jon pointed out this is life for constraining a non-parameterless constructor. However a different solution is to use a factory pattern. This is easily constrainable
interface IFruitFactory<T> where T : BaseFruit {
T Create(int weight);
}
public void AddFruit<T>( IFruitFactory<T> factory ) where T: BaseFruit {
BaseFruit fruit = factory.Create(weight); /*new Apple(150);*/
fruit.Enlist(fruitManager);
}
Yet another option is to use a functional approach. Pass in a factory method.
public void AddFruit<T>(Func<int,T> factoryDel) where T : BaseFruit {
BaseFruit fruit = factoryDel(weight); /* new Apple(150); */
fruit.Enlist(fruitManager);
}
You can do by using reflection:
public void AddFruit<T>()where T: BaseFruit
{
ConstructorInfo constructor = typeof(T).GetConstructor(new Type[] { typeof(int) });
if (constructor == null)
{
throw new InvalidOperationException("Type " + typeof(T).Name + " does not contain an appropriate constructor");
}
BaseFruit fruit = constructor.Invoke(new object[] { (int)150 }) as BaseFruit;
fruit.Enlist(fruitManager);
}
EDIT: Added constructor == null check.
EDIT: A faster variant using a cache:
public void AddFruit<T>()where T: BaseFruit
{
var constructor = FruitCompany<T>.constructor;
if (constructor == null)
{
throw new InvalidOperationException("Type " + typeof(T).Name + " does not contain an appropriate constructor");
}
var fruit = constructor.Invoke(new object[] { (int)150 }) as BaseFruit;
fruit.Enlist(fruitManager);
}
private static class FruitCompany<T>
{
public static readonly ConstructorInfo constructor = typeof(T).GetConstructor(new Type[] { typeof(int) });
}
As an addition to user1471935's suggestion:
To instantiate a generic class by using a constructor with one or more parameters, you can now use the Activator class.
T instance = Activator.CreateInstance(typeof(T), new object[] {...})
The list of objects are the parameters you want to supply. According to Microsoft:
CreateInstance [...] creates an instance of the specified type using the constructor that best matches the specified parameters.
There's also a generic version of CreateInstance (CreateInstance<T>()) but that one also does not allow you to supply constructor parameters.
I created this method:
public static V ConvertParentObjToChildObj<T,V> (T obj) where V : new()
{
Type typeT = typeof(T);
PropertyInfo[] propertiesT = typeT.GetProperties();
V newV = new V();
foreach (var propT in propertiesT)
{
var nomePropT = propT.Name;
var valuePropT = propT.GetValue(obj, null);
Type typeV = typeof(V);
PropertyInfo[] propertiesV = typeV.GetProperties();
foreach (var propV in propertiesV)
{
var nomePropV = propV.Name;
if(nomePropT == nomePropV)
{
propV.SetValue(newV, valuePropT);
break;
}
}
}
return newV;
}
I use that in this way:
public class A
{
public int PROP1 {get; set;}
}
public class B : A
{
public int PROP2 {get; set;}
}
Code:
A instanceA = new A();
instanceA.PROP1 = 1;
B instanceB = new B();
instanceB = ConvertParentObjToChildObj<A,B>(instanceA);
You can use the following command:
T instance = (T)typeof(T).GetConstructor(new Type[0]).Invoke(new object[0]);
Be sure to see the following
reference.
Recently I came across a very similar problem. Just wanted to share our solution with you all. I wanted to I created an instance of a Car<CarA> from a json object using which had an enum:
Dictionary<MyEnum, Type> mapper = new Dictionary<MyEnum, Type>();
mapper.Add(1, typeof(CarA));
mapper.Add(2, typeof(BarB));
public class Car<T> where T : class
{
public T Detail { get; set; }
public Car(T data)
{
Detail = data;
}
}
public class CarA
{
public int PropA { get; set; }
public CarA(){}
}
public class CarB
{
public int PropB { get; set; }
public CarB(){}
}
var jsonObj = {"Type":"1","PropA":"10"}
MyEnum t = GetTypeOfCar(jsonObj);
Type objectT = mapper[t]
Type genericType = typeof(Car<>);
Type carTypeWithGenerics = genericType.MakeGenericType(objectT);
Activator.CreateInstance(carTypeWithGenerics , new Object[] { JsonConvert.DeserializeObject(jsonObj, objectT) });
If you are willing to use a c# precompiler, you could resolve this so that it does have compile time constraints:
// Used attribute
[AttributeUsage(AttributeTargets.Parameter)]
class ResolvedAsAttribute : Attribute
{
public string Expression;
public ResolvedAsAttribute(string expression)
{
this.Expression = expression;
}
}
// Fruit manager source:
class FruitManager {
...
public void AddFruit<TFruit>([ResolvedAs("(int p) => new TFruit(p)")] Func<int,TFruit> ctor = null)where TFruit: BaseFruit{
BaseFruit fruit = ctor(weight); /*new Apple(150);*/
fruit.Enlist(fruitManager);
}
}
// Fruit user source:
#ResolveInclude ../Managers/FruitManager.cs
...
fruitManager.AddFruit<Apple>();
...
Your precompiler would then turn the Fruit user source into:
...
fruitManager.AddFruit<Apple>((int p) => new Apple(p));
...
Using Roslyn, your precompiler could look something like this (here is room for improvement):
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using System.Threading;
using System.Text.RegularExpressions;
public class CsResolveIncludeAnalyser : CSharpSyntaxWalker
{
private List<(string key, MethodDeclarationSyntax node)> methodsToResolve = new List<(string key, MethodDeclarationSyntax node)>();
public List<(string key, MethodDeclarationSyntax node)> Analyse(string source)
{
var tree = CSharpSyntaxTree.ParseText(source);
var syntaxRoot = tree.GetRoot();
Visit(tree.GetRoot());
return methodsToResolve;
}
public override void VisitMethodDeclaration(MethodDeclarationSyntax methodDeclaration)
{
base.VisitMethodDeclaration(methodDeclaration);
if (methodDeclaration.ParameterList.Parameters.Count > 0)
{
foreach (var parm in methodDeclaration.ParameterList.Parameters)
{
var parmHasResolvedAs = parm.AttributeLists.Where((el) => el.Attributes.Where((attr) => attr.Name is IdentifierNameSyntax && ((IdentifierNameSyntax)attr.Name).Identifier.Text.Contains("ResolvedAs")).Any()).Any();
if (parmHasResolvedAs)
{
var name = methodDeclaration.Identifier.ValueText;
methodsToResolve.Add((name, methodDeclaration));
return;
}
}
}
}
}
public class CsSwiftRewriter : CSharpSyntaxRewriter
{
private string currentFileName;
private bool withWin32ErrorHandling;
private Dictionary<string,MethodDeclarationSyntax> methodsToResolve = new Dictionary<string, MethodDeclarationSyntax>();
private Dictionary<string, MethodDeclarationSyntax> getMethodsToResolve(string source, string fileName)
{
Dictionary<string, MethodDeclarationSyntax> methodsToResolve = new Dictionary<string, MethodDeclarationSyntax>();
var path = Path.GetDirectoryName(fileName);
var lines = source.Split(new[] { '\r', '\n' });
var resolveIncludes = (from el in lines where el.StartsWith("#ResolveInclude") select el.Substring("#ResolveInclude".Length).Trim()).ToList();
var analyser = new CsResolveIncludeAnalyser();
foreach (var resolveInclude in resolveIncludes)
{
var src = File.ReadAllText(path + "/" + resolveInclude);
var list = analyser.Analyse(src);
foreach (var el in list)
{
methodsToResolve.Add(el.key, el.node);
}
}
return methodsToResolve;
}
public static string Convert(string source, string fileName)
{
return Convert(source, fileName, false);
}
public static string Convert(string source, string fileName, bool isWithWin32ErrorHandling)
{
var rewriter = new CsSwiftRewriter() { currentFileName = fileName, withWin32ErrorHandling = isWithWin32ErrorHandling };
rewriter.methodsToResolve = rewriter.getMethodsToResolve(source, fileName);
var resolveIncludeRegex = new Regex(#"(\#ResolveInclude)\b");
source = resolveIncludeRegex.Replace(source, "//$1");
var tree = CSharpSyntaxTree.ParseText(source);
var syntaxRoot = tree.GetRoot();
var result = rewriter.Visit(tree.GetRoot());
return "#line 1 \"" + Path.GetFileName(fileName) + "\"\r\n" + result.ToFullString();
}
internal List<string> transformGenericArguments(List<string> arguments, GenericNameSyntax gName, TypeParameterListSyntax typeParameterList)
{
var res = new List<string>();
var typeParameters = typeParameterList.ChildNodes().ToList();
foreach (var argument in arguments)
{
var arg = argument;
for (int i = 0; i < gName.TypeArgumentList.Arguments.Count; i++)
{
var key = typeParameters[i];
var replacement = gName.TypeArgumentList.Arguments[i].ToString();
var regex = new System.Text.RegularExpressions.Regex($#"\b{key}\b");
arg = regex.Replace(arg, replacement);
}
res.Add(arg);
}
return res;
}
const string prefix = "";
internal List<string> extractExtraArguments(MethodDeclarationSyntax methodDeclaration)
{
var res = new List<String>();
foreach (var parm in methodDeclaration.ParameterList.Parameters)
{
foreach (var attrList in parm.AttributeLists)
{
foreach (var attr in attrList.Attributes)
{
if (attr.Name is IdentifierNameSyntax && string.Compare(((IdentifierNameSyntax)attr.Name).Identifier.Text, "ResolvedAs") == 0)
{
var programmCode = attr.ArgumentList.Arguments.First().ToString().Trim();
var trimmedProgrammCode = (programmCode.Length >= 2 && programmCode[0] == '"' && programmCode[programmCode.Length - 1] == '"') ? programmCode.Substring(1, programmCode.Length - 2) : programmCode;
res.Add(prefix + parm.Identifier.Text + ":" + trimmedProgrammCode);
}
}
}
}
return res;
}
internal List<string> extractExtraArguments(MethodDeclarationSyntax methodDeclaration, SimpleNameSyntax name)
{
var arguments = extractExtraArguments(methodDeclaration);
if (name != null && name is GenericNameSyntax)
{
var gName = name as GenericNameSyntax;
return transformGenericArguments(arguments, gName, methodDeclaration.TypeParameterList);
}
return arguments;
}
public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax c_expressionStatement)
{
InvocationExpressionSyntax expressionStatement = (InvocationExpressionSyntax) base.VisitInvocationExpression(c_expressionStatement);
List<string> addedArguments = null;
switch (expressionStatement.Expression)
{
case MemberAccessExpressionSyntax exp:
if (methodsToResolve.ContainsKey(exp.Name?.Identifier.ValueText))
{
addedArguments = extractExtraArguments(methodsToResolve[exp.Name.Identifier.ValueText], exp.Name);
}
break;
case GenericNameSyntax gName:
if (methodsToResolve.ContainsKey(gName.Identifier.ValueText))
{
addedArguments = extractExtraArguments(methodsToResolve[gName.Identifier.ValueText], gName);
}
break;
default:
var name = (from el in expressionStatement.ChildNodes()
where el is GenericNameSyntax
select (el as GenericNameSyntax)).FirstOrDefault();
if (name != default(GenericNameSyntax))
{
if (methodsToResolve.ContainsKey(name.Identifier.ValueText))
{
addedArguments = extractExtraArguments(methodsToResolve[name.Identifier.ValueText], name);
}
}
break;
}
if (addedArguments?.Count > 0)
{
var addedArgumentsString = string.Join(",", addedArguments);
var args = expressionStatement.ArgumentList.ToFullString();
var paras = $"({(expressionStatement.ArgumentList.Arguments.Count > 0 ? string.Join(",", args.Substring(1,args.Length - 2), addedArgumentsString) : addedArgumentsString)})" ;
var argList = SyntaxFactory.ParseArgumentList(paras);
return expressionStatement.WithArgumentList(argList);
}
return expressionStatement;
}
}
The Precompiler could be called using a T4 script, optionally regenerating the source at compile time.
It is still possible, with high performance, by doing the following:
//
public List<R> GetAllItems<R>() where R : IBaseRO, new() {
var list = new List<R>();
using ( var wl = new ReaderLock<T>( this ) ) {
foreach ( var bo in this.items ) {
T t = bo.Value.Data as T;
R r = new R();
r.Initialize( t );
list.Add( r );
}
}
return list;
}
and
//
///<summary>Base class for read-only objects</summary>
public partial interface IBaseRO {
void Initialize( IDTO dto );
void Initialize( object value );
}
The relevant classes then have to derive from this interface and initialize accordingly.
Please note, that in my case, this code is part of a surrounding class, which already has <T> as generic parameter.
R, in my case, also is a read-only class. IMO, the public availability of Initialize() functions has no negative effect on the immutability. The user of this class could put another object in, but this would not modify the underlying collection.