I am trying to implement a generic container that can be indexed both ways:
class DoubleIndexer<T1, T2>
{
public T2 this[T1 key] { get => default; set { } }
public T1 this[T2 key] { get => default; set { } }
}
The problem is that I get compile-time errors when I try to use an instance with the same type for T1 and T2:
var int_int = new DoubleIndexer<int, int>();
int_int[1] = 13; // CS0121: The call is ambiguous between the following
// methods or properties: 'DoubleIndexer<T1, T2>.this[T1]'
// and 'DoubleIndexer<T1, T2>.this[T2]'
There is no problem when the types T1 and T2 are different:
var int_string = new DoubleIndexer<int, string>();
int_string[1] = "Hello"; // OK
int_string["Hello"] = 1; // OK
var int_byte = new DoubleIndexer<int, byte>();
int_byte[1] = 13; // OK
int_byte[(byte)13] = 1; // OK
Is there any workaround for this problem, or I am forced to change the interface of my generic class?
Coders are used to Dictionary<int, string> which works in one direction Key > Value. Given the language limitation, you should go with an approach that is more intuitive, predictable, and fits in with prior art.
Sub-interface only for the reversed situation
Code:
var lookupByIDReversible = new DoubleIndexer<int, string>();
...
lookupByIDReversible[1] = "hello";
lookupByIDReversible.Reverse["hello"] = 1;
You might think of some better language.
I'll leave the implementation up to you.
RecordSet-centric with Nx indexers possible
Another approach entirely, would make use of a recordset pattern that can emit indexers that remain linked to the set. The set is the hub for all indexers.
class Message
{
public int ID;
public int ToUserID;
public int FromUserID
public string MessageBody;
public DateTime UpdatedAt;
}
var messages = new RecordSet<Message>();
messages.AddRange(...);
var byToUserID = messages.IndexBy(r => r.ToUserID);
byToUserID[7].FromUserID = 8; //Found member assignment
byToUserID[9] = byToUserID[10]; //Assignment (probably not desirable)
var byMessageBody = messages.IndexBy(r => r.MessageBody);
byMessageBody["hello"].ToUserID = 11;
byToUserID[12] = new Message() { MessageBody = "test1", ... }; //Where ToUserID in the supplied object will be overwritten.
byMessageBody["test1"].ToUserID == 12; //Evaluates to true
The benefit of this, is you get a semantic API that should be more predictable, but it also scales beyond 2 types.
The workaround can be based on explicit interfaces:
2nd version
public interface IDirectIndex<T1, T2>
{
T2 this[T1 key] { get; set; }
}
public interface IInvertedIndex<T1, T2>
{
T1 this[T2 key] { get; set; }
}
internal class DoubleIndexer<T1, T2> : IDirectIndex<T1, T2>, IInvertedIndex<T1, T2>
{
T2 IDirectIndex<T1, T2>.this[T1 key]
{
get => default;
set { Console.WriteLine($"T2 IDirectIndex<T1, T2>.this[T1 key]: {value}"); }
}
T1 IInvertedIndex<T1, T2>.this[T2 key]
{
get => default;
set { Console.WriteLine($"T1 IInvertedIndex<T1, T2>.this[T2 key]: {value}"); }
}
}
Test examples:
var int_string = new DoubleIndexer<int, string>();
((IDirectIndex<int, string>)int_string)[1] = "Hello"; // OK
((IInvertedIndex<int, string>)int_string)["Hello"] = 1; // OK
var int_byte = new DoubleIndexer<int, byte>();
((IInvertedIndex<int, byte>)int_byte)[1] = 134567; // OK
((IDirectIndex<int, byte>)int_byte)[134567] = 41; // OK
var int_int = new DoubleIndexer<int, int>();
((IInvertedIndex<int, int>)int_int)[1] = 1345; // OK
((IDirectIndex<int, int>)int_int)[13] = 5431; // OK
1st version
public interface IIndex<T1, T2>
{
T2 this[T1 key] { get; set; }
}
internal class DoubleIndexer<T1, T2> : IIndex<T1, T2>
{
public T1 this[T2 key]
{
get => default;
set { Console.WriteLine($"T1 this[T2 key]: {value}"); }
}
T2 IIndex<T1, T2>.this[T1 key]
{
get => default;
set { Console.WriteLine($"T2 IIndex<T1, T2>.this[T1 key]: {value}"); }
}
}
Test examples:
var int_string = new DoubleIndexer<int, string>();
((IIndex<int, string>)int_string)[1] = "Hello"; // OK
int_string["Hello"] = 1; // OK
var int_byte = new DoubleIndexer<int, byte>();
int_byte[1] = 134567; // OK
((IIndex<int, byte>)int_byte)[134567] = 41; // OK
var int_int = new DoubleIndexer<int, int>();
int_int[1] = 1345; // OK
((IIndex<int, int>)int_int)[13] = 5431; // OK
MSDN Indexers in Interfaces:
the fully qualified name is only needed to avoid ambiguity when the
class is implementing more than one interface with the same indexer
signature
Related
I am wondering if there is an alternative to dot notation in C#. For instance, in Javascript, I can have an object like this:
const myObj = { foo: "bar" }
And then I can reference it like this:
let x = "foo";
let y = myObj[x]; //sets y = "bar"
Is this possible in C#? I have not found anything of the sort, but am wondering if there are alternatives that would function similarly.
You can implement an indexer in your class:
public class A
{
public int X { get; set; }
public string Y { get; set; }
public object this[string name]
{
get => GetType().GetProperty(name).GetValue(this, null);
set => GetType().GetProperty(name).SetValue(this, value);
}
}
Then use it:
var a = new A();
a["X"] = 10;
a["Y"] = "abc";
Console.WriteLine(a.X);
Console.WriteLine(a.Y);
You can have something similar using dynamic but you have to explicitly get the dictionary interface to use the array syntax.
dynamic myObject = new ExpandoObject();
myObject.greeting = "hello";
IDictionary<string, object> myDict = myObject;
Console.WriteLine(myDict["greeting"]);
Note that it works in both directions. You can add that after the previous code:
myDict["name"] = "Joe";
Console.WriteLine(myObject.name);
You can have both syntax if you don't mind having an intermediate object like myObject.something.name.
The code would look like:
void Main()
{
BothSyntax test= new BothSyntax();
test.dyn.greeting = "Hi";
Console.WriteLine(test["greeting"]);
test["name"] = "Joe";
Console.WriteLine(test.dyn.name);
}
class BothSyntax
{
public dynamic dyn => eo;
private ExpandoObject eo = new ExpandoObject();
public object this[string key]
{
get
{
return ((IDictionary<string, object>)eo)[key];
}
set
{
((IDictionary<string, object>)eo)[key] = value;
}
}
}
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[] { });
Is this the fastest way to update a property using reflection? Assume the property is always an int:
PropertyInfo counterPropertyInfo = GetProperty();
int value = (int)counterPropertyInfo.GetValue(this, null);
counterPropertyInfo.SetValue(this, value + 1, null);
I did some benchmarking here when you know the type arguments (a non generic approach wont be very different). CreateDelegate would be the fastest approach for a property if you can't directly access it. With CreateDelegate you get a direct handle to GetGetMethod and GetSetMethod of the PropertyInfo, hence reflection is not used every time.
public static Func<S, T> BuildGetAccessor<S, T>(Expression<Func<S, T>> propertySelector)
{
return propertySelector.GetPropertyInfo().GetGetMethod().CreateDelegate<Func<S, T>>();
}
public static Action<S, T> BuildSetAccessor<S, T>(Expression<Func<S, T>> propertySelector)
{
return propertySelector.GetPropertyInfo().GetSetMethod().CreateDelegate<Action<S, T>>();
}
// a generic extension for CreateDelegate
public static T CreateDelegate<T>(this MethodInfo method) where T : class
{
return Delegate.CreateDelegate(typeof(T), method) as T;
}
public static PropertyInfo GetPropertyInfo<S, T>(this Expression<Func<S, T>> propertySelector)
{
var body = propertySelector.Body as MemberExpression;
if (body == null)
throw new MissingMemberException("something went wrong");
return body.Member as PropertyInfo;
}
So now you call:
TestClass cwp = new TestClass();
var access = BuildGetAccessor((TestClass t) => t.AnyValue);
var result = access(cwp);
Or even better you can encapsulate the logic in a dedicated class to have a get and set methods on it.
Something like:
public class Accessor<S>
{
public static Accessor<S, T> Create<T>(Expression<Func<S, T>> memberSelector)
{
return new GetterSetter<T>(memberSelector);
}
public Accessor<S, T> Get<T>(Expression<Func<S, T>> memberSelector)
{
return Create(memberSelector);
}
public Accessor()
{
}
class GetterSetter<T> : Accessor<S, T>
{
public GetterSetter(Expression<Func<S, T>> memberSelector) : base(memberSelector)
{
}
}
}
public class Accessor<S, T> : Accessor<S>
{
Func<S, T> Getter;
Action<S, T> Setter;
public bool IsReadable { get; private set; }
public bool IsWritable { get; private set; }
public T this[S instance]
{
get
{
if (!IsReadable)
throw new ArgumentException("Property get method not found.");
return Getter(instance);
}
set
{
if (!IsWritable)
throw new ArgumentException("Property set method not found.");
Setter(instance, value);
}
}
protected Accessor(Expression<Func<S, T>> memberSelector) //access not given to outside world
{
var prop = memberSelector.GetPropertyInfo();
IsReadable = prop.CanRead;
IsWritable = prop.CanWrite;
AssignDelegate(IsReadable, ref Getter, prop.GetGetMethod());
AssignDelegate(IsWritable, ref Setter, prop.GetSetMethod());
}
void AssignDelegate<K>(bool assignable, ref K assignee, MethodInfo assignor) where K : class
{
if (assignable)
assignee = assignor.CreateDelegate<K>();
}
}
Short and simple. You can carry around an instance of this class for every "class-property" pair you wish to get/set.
Usage:
Person p = new Person { Age = 23 };
var ageAccessor = Accessor<Person>(x => x.Age);
int age = ageAccessor[p]; //gets 23
ageAccessor[p] = 45; //sets 45
Bit bad use of indexers here, you may replace it with dedicated "Get" and "Set" methods, but very intuitive to me :)
To avoid having to specify type each time like,
var ageAccessor = Accessor<Person>(x => x.Age);
var nameAccessor = Accessor<Person>(x => x.Name);
var placeAccessor = Accessor<Person>(x => x.Place);
I made the base Accessor<> class instantiable, which means you can do
var personAccessor = new Accessor<Person>();
var ageAccessor = personAccessor.Get(x => x.Age);
var nameAccessor = personAccessor.Get(x => x.Name);
var placeAccessor = personAccessor.Get(x => x.Place);
Having a base Accessor<> class means you can treat them as one type, for eg,
var personAccessor = new Accessor<Person>();
var personAccessorArray = new Accessor<Person>[]
{
personAccessor.Get(x => x.Age),
personAccessor.Get(x => x.Name),
personAccessor.Get(x => x.Place);
};
You should look at FastMember (nuget, source code], it's really fast comparing to reflection.
I've tested these 3 implementations:
PropertyInfo.SetValue
PropertyInfo.SetMethod
FastMember
The benchmark needs a benchmark function:
static long Benchmark(Action action, int iterationCount, bool print = true)
{
GC.Collect();
var sw = new Stopwatch();
action(); // Execute once before
sw.Start();
for (var i = 0; i <= iterationCount; i++)
{
action();
}
sw.Stop();
if (print) System.Console.WriteLine("Elapsed: {0}ms", sw.ElapsedMilliseconds);
return sw.ElapsedMilliseconds;
}
A fake class:
public class ClassA
{
public string PropertyA { get; set; }
}
Some test methods:
private static void Set(string propertyName, string value)
{
var obj = new ClassA();
obj.PropertyA = value;
}
private static void FastMember(string propertyName, string value)
{
var obj = new ClassA();
var type = obj.GetType();
var accessors = TypeAccessor.Create(type);
accessors[obj, "PropertyA"] = "PropertyValue";
}
private static void SetValue(string propertyName, string value)
{
var obj = new ClassA();
var propertyInfo = obj.GetType().GetProperty(propertyName);
propertyInfo.SetValue(obj, value);
}
private static void SetMethodInvoke(string propertyName, string value)
{
var obj = new ClassA();
var propertyInfo = obj.GetType().GetProperty(propertyName);
propertyInfo.SetMethod.Invoke(obj, new object[] { value });
}
The script itself:
var iterationCount = 100000;
var propertyName = "PropertyA";
var value = "PropertyValue";
Benchmark(() => Set(propertyName, value), iterationCount);
Benchmark(() => FastMember(propertyName, value), iterationCount);
Benchmark(() => SetValue(propertyName, value), iterationCount);
Benchmark(() => SetMethodInvoke(propertyName, value), iterationCount);
Results for 100 000 iterations:
Default setter : 3ms
FastMember: 36ms
PropertyInfo.SetValue: 109ms
PropertyInfo.SetMethod: 91ms
Now you can choose yours !!!
Just be sure that you are caching the PropertyInfo somehow, so that you aren't repeatably calling type.GetProperty. Other than that it would probably be faster if you created a delegate to a method on the type that performed the increment, or like Teoman suggested make the type implement an interface and use that.
I need to calculate a whole bunch of averages on an List of Surveys. The surveys have lots of properties that are int and double valued. I am creating a business object to handle all the calculations (there are like 100) and I'd rather not code 100 different methods for finding the average for a particular property.
I'd like to be able to have the UI pass a string (representing the property) and have the the business object return an average for that property.
So, like...
int AverageHeightInInches = MyObject.GetIntAverage("HeightInInches");
.
.
.
Then have linq code to calculate the result.
Thanks!
I have created this little example, it uses the System.Linq.Expression namespace to create a function that can calculate averages based on the property name. The function can be cached for later use, reflection is only used to create the function, not each time the function is executed.
EDIT: I removed the existing reflection example and updated the current example to show the ability to walk a list of properties.
static class Program
{
static void Main()
{
var people = new List<Person>();
for (var i = 0; i < 1000000; i++)
{
var person = new Person { Age = i };
person.Details.Height = i;
person.Details.Name = i.ToString();
people.Add(person);
}
var averageAgeFunction = CreateIntegerAverageFunction<Person>("Age");
var averageHeightFunction = CreateIntegerAverageFunction<Person>("Details.Height");
var averageNameLengthFunction = CreateIntegerAverageFunction<Person>("Details.Name.Length");
Console.WriteLine(averageAgeFunction(people));
Console.WriteLine(averageHeightFunction(people));
Console.WriteLine(averageNameLengthFunction(people));
}
public static Func<IEnumerable<T>, double> CreateIntegerAverageFunction<T>(string property)
{
var type = typeof(T);
var properties = property.Split('.'); // Split the properties
ParameterExpression parameterExpression = Expression.Parameter(typeof(T));
Expression expression = parameterExpression;
// Iterrate over the properties creating an expression that will get the property value
for (int i = 0; i < properties.Length; i++)
{
var propertyInfo = type.GetProperty(properties[i]);
expression = Expression.Property(expression, propertyInfo); // Use the result from the previous expression as the instance to get the next property from
type = propertyInfo.PropertyType;
}
// Ensure that the last property in the sequence is an integer
if (type.Equals(typeof(int)))
{
var func = Expression.Lambda<Func<T, int>>(expression, parameterExpression).Compile();
return c => c.Average(func);
}
throw new Exception();
}
}
public class Person
{
private readonly Detials _details = new Detials();
public int Age { get; set; }
public Detials Details { get { return _details; } }
}
public class Detials
{
public int Height { get; set; }
public string Name { get; set; }
}
Here is an example to do that.
class Survey
{
public int P1 { get; set; }
}
class MyObject
{
readonly List<Survey> _listofSurveys = new List<Survey> { new Survey { P1 = 10 }, new Survey { P1 = 20 } };
public int GetIntAverage(string propertyName)
{
var type = typeof(Survey);
var property = type.GetProperty(propertyName);
return (int)_listofSurveys.Select(x => (int) property.GetValue(x,null)).Average();
}
}
static void Main(string[] args)
{
var myObject = new MyObject();
Console.WriteLine(myObject.GetIntAverage("P1"));
Console.ReadKey();
}
if you are using linq2sql i would suggest DynamicLinq
you could then just do
datacontext.Surveys.Average<double>("propertyName");
the dynamic linq project provides the string overloads to IQueryable.
You can do this without reflection (both int and double are supported):
public static double Average(this IEnumerable<Survey> surveys, Func<Survey, int> selector)
{
return surveys.Average(selector);
}
public static double Average(this IEnumerable<Survey> surveys, Func<Survey, double> selector)
{
return surveys.Average(selector);
}
Usage:
var average1 = surveys.Average(survey => survey.Property1);
var average2 = surveys.Average(survey => survey.Property2);
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.