Returning references from Generic Arrays - c#

I've got a class which holds a list of ComponentBase. Component sub classes ComponentBase.
public abstract class ComponentBase
{
public Type Type;
public dynamic Value;
public uint EntityID;
}
public class Component<T> : ComponentBase
{
public new Type Type;
public new T Value;
public new uint EntityID;
}
I need a way to retrieve a ref to a Component<T>.Value in the GetComponentOnEntity method and I can't seem to find it. Im not very good at generics so I'll put this question to the pros.
public class ComponentDatabase
{
ComponentBase[] components;
private int componentIndex;
public T AddComponentToEntity<T>(T component, Entity entity) where T : new()
{
var x = component != null ? component : new T();
var comp = new Component<T> { EntityID = entity.Id, Type = typeof(T), Value = x };
components[componentIndex++] = comp;
return x;
}
public ref T GetComponentOnEntity<T>(Entity entity) where T : new()
{
return ref components.Where(x => x.EntityID == entity.Id && x.Type == typeof(T)).First().Value;
}
}
Ive had a long night and I feel like there is a simple solution but I really can't find it. Any help would be greatly appreciated.

Fundamentally, the issue with your code is that you are trying to return a reference to the wrong member of the object. You are returning the member with the dynamic type, when you actually need the member having the type T.
Your original example is equivalent to this simpler one:
class Base
{
public int Id;
public dynamic Value;
public Base(int id, dynamic value)
{
Id = id;
Value = value;
}
public override string ToString() => $"{{Id: {Id}, Value: {Value}}}";
}
class Derived<T> : Base
{
public new int Id;
public new T Value;
public Derived(int id, T value) : base(id, value) { }
}
static void Main(string[] args)
{
Derived<string>[] array = new[]
{
new Derived<string>(0, "Zero"),
new Derived<string>(1, "One"),
new Derived<string>(2, "Two"),
};
ref string valueRef = ref GetElement<string>(array, 1);
valueRef = "Three";
WriteLine(string.Join<Base>(Environment.NewLine, array));
}
private static ref T GetElement<T>(Base[] array, int id)
{
// error CS8151: The return expression must be of type 'T' because this method returns by reference
return ref array.Where(x => x.Id == id).First().Value;
}
The problem is simply that you are trying to return the base class field, which has the type dynamic rather than T.
To fix that, you need to cast the object so that you get the field from the derived type instead:
private static ref T GetElement<T>(Base[] array, int id)
{
return ref ((Derived<T>)array.Where(x => x.Id == id).First()).Value;
}
Or, in your original example:
public ref T GetComponentOnEntity<T>(Entity entity) where T : new()
{
return ref ((Component<T>)components.Where(x => x.EntityID == entity.Id && x.Type == typeof(T)).First()).Value;
}
Now, all that said: I urge you to rethink the design. Perhaps you've omitted some code that initializes the base Value field identically to the derived Value field. But even if so (and that's wasteful enough), there's nothing that prevents those fields from being assigned differently later on. It's not just wasteful, it's also likely to lead to bugs to have an object that has two copies of every value in it, especially when those values are not read-only.
Member hiding (i.e. using the new keyword as you have in your data structures) should be avoided at all costs. It only leads to confusion and will almost certainly result in any number of hard-to-find, hard-to-fix bugs later down the road. The issue you've run into here is just the tip of the iceberg, but is a good example of how confusing things can be when an object has two different members that have the same name.
In addition, ref return values should be used very sparingly, and only when absolutely necessary (e.g. a critical performance issue that can be fixed only using ref return). There's context missing from your question of course, and so maybe you do have a really good reason for using that feature here. But just based on the names in the code that's present, it seems likely to me that you could get the code to work just fine without either of the oddities in the code now (the member hiding and the ref return values).

Related

Constrain generic type on a method to be any class that is derived from any variant form of an abstract generic base class

So I've been searching and searching for the solution to this problem, and I'm painfully aware that perhaps I just don't know how to ask the question in the right way to find an answer, so I'm more than happy, if there's an existing solution, to be pointed to the relevant article (or even just to get a better understanding/grasp of how to say what it is that I'm trying to find out!)
That being said, I have an abstract base class for managing / handling external, XML-based source data in generic ways and to act as the foundation for a ton of derived classes that sit on top of it and contexualize this raw data into use-specific formats.
In another class, intended to be an abstract foundation for a series of other classes whose jobs are to manage data that's stored in the first set of classes I described. In this second foundational class, have a method into which I want to be able to pass every and any possible class that is derived from my abstract base data class without that method having any foreknowledge of what the incoming class actually is (other than that it must be derived from the aforementioned archetype data classes).
This is obviously pretty confusing and is a difficult thing to try and explain/describe in words (thus my problem trying to ask the right question to find an answer) so below is a (greatly) pared-down code sample that I hope might better illustrate what I'm trying to say...
internal abstract class PrototypeDataClass
{
// intention is to hold and manage one generic record of unknown data.
protected List<KeyValuePair<string, string>> _data = new List<KeyValuePair<string,string>>();
protected PrototypeDataClass(PrototypeDataClass source) =>
this._data.AddRange(source._data.ToArray());
// Expects an XmlNode containing field data...
protected PrototypeDataClass(XmlNode source)
{
XmlNodeCollection nodes = source.GetElementsByTagName("field");
foreach (XmlNode node in nodes)
{
string key = XmlNode.Attributes["field"].Value,
value = XmlNode.InnerText;
this.Add(key,value);
}
}
public int Count => this._data.Count;
public string this[string index]
{
get {
int i = FindFieldByName(index);
if ((i<0) || (i>=Count)) throw new ArgumentOutOfRangeException();
return this[i];
}
set => this.Add(index,value);
}
protected int FindFieldByName(string fieldname)
{
int i=-1; while ((++i < Count) && !_data[i].Key.Equals(fieldname, StringComparison.InvariantCultureIgnoreCase));
return (i < Count) ? i : -1;
}
public void Add(string key, string value) =>
Add(new KeyValuePair<string,string>(key, value));
public void Add(KeyValuePair newData)
{
int i = FindFieldByName(newData.Key);
if (i<0)
this._data.Add(newData);
else
this._data[i] = newData;
}
public abstract string FormattedDisplayLine();
public static bool IsDerivedType(dynamic test) =>
IsDerivedType(test.GetType());
public static bool IsDerivedType(Type test) =>
(test == typeof(Object)) || (test is null) ? false :
(test.BaseType == typeof(PrototypeDataClass)) ? true : IsDerivedType(test.BaseType);
}
// Problem 1: I would like the WHERE constraint here to facilitate using
// only derivatives of PrototypeDataClass for T...
internal abstract class PrototypeDataGroup<T> where T : new()
{
List<T> _data = new List<T>();
protected PrototypeDataGroup()
{
// A clunky workaround to validate that the supplied generic type is
// derived from my prototype...
if (!PrototypeDataClass.IsDerivedType(typeof(T)))
throw new Exception(typeof(T).Name + " is not derived from PrototypeDataClass.");
}
protected PrototypeDataGroup(T[] sourceData)
{
// Same clunky workaround...
if (!PrototypeDataClass.IsDerivedType(typeof(T)))
throw new Exception(typeof(T).Name + " is not derived from PrototypeDataClass.");
foreach(T line in sourceData)
this.Add(line);
}
protected PrototypeDataGroup(XmlDocument doc)
{
// Same clunky workaround...
if (!PrototypeDataClass.IsDerivedType(typeof(T)))
throw new Exception(typeof(T).Name + " is not derived from PrototypeDataClass.");
XmlNodeCollection nodes = doc.GetElementsByTagName("rows");
foreach (XmlNode node in nodes)
this._data.Add(new PrototypeDataClass(node));
}
public int Count => this._data.Count;
public T this[int index] => this._data[index];
public void Add(T item) =>
this._data.Add(item);
public abstract string[] FormattedDisplayLines();
}
internal class MySpecificData : PrototypeDataClass
{
public MySpecificData() : base() { }
public MySpecificData(PrototypeDataClass source) : base(source) { }
public MySpecificData(XmlNode source) : base(source) { }
public MySpecificData(KeyValuePair data) : base() =>
this.Add(data);
public MySpecificData(string key, string value) : base() =>
this.Add(key, value);
// Code to manage / present the generic data in MySpecific ways...
public override string FormattedDisplayLine() =>
_data["specificField1"] + ": " + _data["specificField2"];
}
internal class MySpecificDataGroup : PrototypeDataGroup<MySpecificData>
{
public MySpecificDataGroup() : base() { }
public MySpecificDataGroup(XmlDocument doc) : base(doc) { }
public MySpecificDataGroup(MySpecificData[] source) : base(source) { }
// present / manage the collection in MySpecific ways
public override string[] FormattedDisplayLines()
{
List<string> lines = new List<string>();
for(int i=0; i<Count; i++)
lines.Add(new MySpecificData(this._data[i]).FormattedDisplayLine());
return lines.ToArray();
}
}
// This class's purpose is to provide the foundation for another set of
// classes that are designed to perform work using the data held in various
// derivations of PrototypeDataGroup<T>
internal abstract class SomeOtherClassFoundation
{
XmlDocument _doc;
public SomeOtherClassFoundation(XmlDocument source) =>
this._doc = source;
// Problem 2: would like to simply constrain Y here to EVERY/ANY
// possible derivation of PrototypeDataGroup, but when I try that,
// i.e. "public void DisplayDoc<Y>(string title) where Y : PrototypeDataGroup, new()"
// the compiler spits out an error that appears to demand that I
// pre-declare every individual allowable "Y" variant separately:
// "Using the generic type 'PrototypeDataGroup<T>' requires at least 1 type arguments"
// Soo: "public void DisplayDoc<Y>(string title) where Y : PrototypeDataGroup<MySpecificDataGroup>, PrototypeDataGroup<MyOtherSpecificDataGroup>, new()"
// As there could ultimately be dozens of such derived classes, having
// to maintain such a list manually is beyond daunting and seems
// absurd. Is there no way to specify:
// "where Y : PrototypeDataGroup<>, new()" (for any/all values of '<>'?)
protected void DisplayContents<Y>(string title) where Y : new()
{
// If I use "Y" here in lieu of "dynamic", the code won't even
// compile as the compiler decides that it's absolutely impossible for
// the Y type to have either the "Count" or "FormattedDisplayLines" methods.
// By using "dynamic", it at least waits until runtime to make that evaluation
// then reacts accordingly (though usually still badly)...
dynamic work = new Y();
if (work.Count > 0)
{
Console.WriteLn("Displaying " + work.Count.ToString() + " records:\r\n"+ title);
foreach (string line in work.FormattedDisplayLines())
Console.WriteLn(line);
}
}
}
internal class SomeOtherClassForMySpecificData : SomeOtherClassFoundation
{
public SomeOtherClassForMySpecificData(XmlDocument source) : base(source) { }
public Show()
{
string title = "Specific Field 1 | Specific Field 2\r\n".PadRight(80,'=');
base.DisplayContents<MySpecificData>(title);
}
}
So, in addition to the things that I've mentioned in comments above, the compiler also rejects that call to base.DisplayContents<MySpecificData>(title); with the error:
Error CS0310 'MySpecificData' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'Y' in the generic type or method 'SomeOtherClassFoundation.DisplayContents(string)'
Clearly MySpecificData HAS a public, parameterless constructor, and, while it is DERIVED from an abstract base type, it is not, itself, one...
Also, there are tons of problems with the dynamic implementation of the derived classes within the DisplayContents(string) function, from not recognizing the methods requested, to attempting to call the prototype methods instead of the overriding ones...
This has been killing me for three days now, and it's pretty obvious that stuff is happening here that I don't understand, so any pointers, insights, suggestions and/or clarifications would be greatly appreciated!
I didn't get what you actually want to do. But reading your code, I made some changes that seems can help:
Add a constraint to PrototypeDataGroup:
internal abstract class PrototypeDataGroup<T>
where T : PrototypeDataClass, new()
Add a constraint to DisplayContents method:
DisplayContents<Y,T>(string title)
where Y : PrototypeDataGroup<T>, new()
where T: PrototypeDataClass, new()
Make the call to DisplayContents method as below:
base.DisplayContents<MySpecificDataGroup, MySpecificData>(title);

Mapping different enums together

First, here is why this question is not a duplicate:
I know that multiple questions about converting one enum to another have been asked on SO, I even answered one of them myself, but all the questions I've found on this topic had some way of comparing the different enum values (whether by name or by value). In my particular case, I don't know the values, and the names don't match.
As a part of a GitHub project I'm working on, called ADONETHelper, that's designed to minimize code repetition when working with Ado.Net, I came face to face with the need to translate values between unrelated enums. This is to allow the same code to work with OleDb, Odbc, and SqlClient (and hopefully in the future OracleClient and MySqlClient as well).
What I'm trying to do is create a unification of different enums - specifically - enums that describe sql parameters data types.
Currntly, I am supporting 4 enums -
System.Data.DbType,
System.Data.SqlClient.SqlDbType,
System.Data.OleDb.OleDbType,
System.Data.Odbc.OdbcType
but if I want to add support for OracleClient or MySqlClient, I'll have to work pretty hard to add System.Data.OracleClient.OracleType Or MySql.Data.MySqlClient.MySqlDbType.
So I'm looking for a more elegant way of doing this then I came up with.
Here is my current code (It works great, but as I wrote, it's hard to add support for new enums):
So first, I have defined my own enum called ADONETType. It has entries such as Boolean, Byte, Binary, Char etc'.
Then I've created a static class called DBTypeConverter to provide extension methods to this enum, so that it's value could be converted to the other enums.
This is what this class looks like:
internal static class DBTypeConverter
{
#region private members
private static List<DbTypeMap> _Map;
#endregion private members
#region static constructor
static DBTypeConverter()
{
_Map = new List<DbTypeMap>()
{
new DbTypeMap(ADONETType.Boolean, DbType.Boolean, SqlDbType.Bit, OleDbType.Boolean, OdbcType.Bit),
new DbTypeMap(ADONETType.Byte, DbType.Byte, SqlDbType.TinyInt, OleDbType.UnsignedTinyInt , OdbcType.TinyInt),
new DbTypeMap(ADONETType.Binary, DbType.Binary, SqlDbType.Binary, OleDbType.Binary, OdbcType.Binary),
// ... more of the same here ...
new DbTypeMap(ADONETType.Xml, DbType.Xml, SqlDbType.Xml, null, null)
};
}
#endregion static constructor
#region methods
internal static DbType ToDbType(this ADONETType type)
{
return type.ConvertTo<DbType>();
}
internal static SqlDbType ToSqlType(this ADONETType type)
{
return type.ConvertTo<SqlDbType>();
}
internal static OleDbType ToOleDbType(this ADONETType type)
{
return type.ConvertTo<OleDbType>();
}
internal static OdbcType ToOdbcType(this ADONETType type)
{
return type.ConvertTo<OdbcType>();
}
private static dynamic ConvertTo<T>(this ADONETType type)
{
var returnValue = _Map.First(m => m.ADONETType == type).GetValueByType(typeof(T));
if(returnValue != null)
{
return returnValue;
}
throw new NotSupportedException(string.Format("ADONETType {0} is not supported for {1}", type, typeof(T)));
}
#endregion methods
#region private struct
private struct DbTypeMap
{
#region ctor
public DbTypeMap(ADONETType adonetType, DbType? dbType, SqlDbType? sqlDbType, OleDbType? oleDbType, OdbcType? odbcType)
: this()
{
ADONETType = adonetType;
DbType = dbType;
SqlDbType = sqlDbType;
OleDbType = oleDbType;
OdbcType = odbcType;
}
#endregion ctor
#region properties
internal ADONETType ADONETType { get; private set; }
internal DbType? DbType { get; private set; }
internal SqlDbType? SqlDbType { get; private set; }
internal OleDbType? OleDbType { get; private set; }
internal OdbcType? OdbcType { get; private set; }
#endregion properties
#region methods
internal dynamic GetValueByType(Type type)
{
if (type == typeof(ADONETType))
{
return this.ADONETType;
}
if(type == typeof(DbType))
{
return this.DbType;
}
if (type == typeof(SqlDbType))
{
return this.SqlDbType;
}
if (type == typeof(OleDbType))
{
return this.OleDbType;
}
if (type == typeof(OdbcType))
{
return this.OdbcType;
}
return null;
}
#endregion methods
}
#endregion private struct
}
Now, as you can see, In order to provide support for, say, OracleClient, I'll have to do the following:
Add a property for OracleType in the DbTypeMap private struct.
Change the DbTypeMap constructor to accept also the oracle type.
Add another case to the switch in GetValueByType method.
Add the oracle type to the static constructor of DBTypeConverter.
Add a method (internal static OracleType ToOracleType(this ADONETType type)) to DBTypeConverter.
Obvoisuly, this is a lot of work and I would much rather find another way to unify these enums, so adding support to new clients will be easier.
This is when your experties come in to play.
Assuming you really need this (consider Jeroen's comment, if not then you may reuse this for something else...) you can simplify things using a list of equivalences. It's simply a list of arrays where array items are equivalent. I'm using an array instead of a class because I do not need to add properties and ctor arguments when adding a new equivalence. To store the equivalence I'm using the special Enum base class but also object works pretty well (no need, AFAIK, for dynamic).
Finding a conversion is then just matter of a search inside these lists (code here is more explicative than performance wise):
public static TTo ConvertTo<TTo>(Enum value)
{
var set = Mapping.FirstOrDefault(values => Array.IndexOf(values, value) != -1);
if (set == null)
throw new InvalidOperationException($"Value {value} is unknown");
return (TTo)(object)set.First(x => x.GetType() == typeof(TTo));
}
Populate Mapping list as required, it may be defined, for example, as:
private static List<Enum[]> Mapping = new List<Enum[]>
{
new Enum[] { ADONETType.Byte, DbType.Byte, SqlDbType.TinyInt },
new Enum[] { ADONETType.Boolean, DbType.Boolean, SqlDbType.Bit },
new Enum[] { ADONETType.Binary, DbType.Binary, SqlDbType.Binary },
new Enum[] { ADONETType.Xml, DbType.Xml },
};
Note that ugly double cast (TTo)(object)...ahhhh .NET Generics...a better solution is welcome. To support a new equivalence you still need to map all enum's values into this table, annoying but localized in one single place. If conversion isn't possible (value value isn't defined anywhere) or there is not a known conversion to TTo (for example the last DbType.Xml) then InvalidOperationException is thrown.

Find a class that it has a specific property value

Consider I have these classes
class BaseClass
{
public int Variable {get; set;}
}
class Class1:BaseClass
{
public Class1()
{
Variable=1;
}
}
class Class2:BaseClass
{
public Class2()
{
Variable=2;
}
}
In another place I want to do this:
public BaseClass MyMethod(int i)
{
//I want if i is 1 this method returns Class1
//And if i is 2 this method returns Class2.
}
A solution is using switch statement. But my namespace has a lot of class and using switch results a lot of code lines.
Your comment "But my namespace has a lot of class and using switch results a lot of code lines." tells me that you are doing something wrong.
This is classic problem, easily solved by factory pattern, using switch would be the best solution here:
switch(num) {
case 1: return new Class1();
case 2: return new Class2();
default: throw new ArgumentException();
}
Maybe you should split your namespace?
Other solution with is a bit ugly because you will lose compile time checking, is to use Activator:
return (BaseClass)Activator.CreateInstance("AssemblyName", "Class" + num)
Based on comment, 100 classes and must select one.
public static class AmazingFactory {
private static IDictionary<int, Type> _num2Type;
private static void InitializeFactory() {
var type = typeof(BaseClass);
// get all subclasses of BaseClass
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
foreach(var type in types) {
int numberAtTheEnd = int.Parse(Regex.Match(type.Name, #"\d+$").Value);
_num2Type[numberAtTheEnd] = type;
}
}
public static BaseClass Create(int num) {
if (_num2Type == null)
InitializeFactory();
return (BaseClass)Activator.CreateInstance(_num2Type[num]);
}
}
Looks like you don't want to return a class, but rather an instance of a class. The next question is where do you want to get your object from? If they are stored in some collection like
items = new List<BaseClass>();
items.add(new Class1());
items.add(new Class2());
then you can write something like
public BaseClass MyMethod(int i)
{
return items.First(item=>item.Variable == i);
}
If you want to create a new instance with each call to MyMethod than you'll have to use switch\if (or use Reflection, but that's not a recommended approach)

Return instance using reflection in C#

A sample code I tried to return an instance of class is given below.
public object getConstructorclass(int i)
{
if(i==1)
{
Type type = Type.GetType("test1");
}else
{
Type type = Type.GetType("test2");
}
return Activator.CreateInstance(type);
}
var objcls = getConstructorclass(1);
objcls.callclass();//error occured
How can I mention the class type here since the type is not known at compile time but it will decided at runtime.In the above example i just pass a value 1 (it can be anything and that class will be called accordingly), and the class test1 called.
here I will get an error on the line objcls.callclass(), because objcls is an object instance that doesn't have a callclass()method.
How can I restructure this piece of code? My aim is if I mention a class in the getConstructorclass() method, an object should be returned so as to use it in the further code to invoke the members of that class.
If you know that your classes will have this method, you should use a common interface for them and implement it accordingly. Then you will work with classes that you have made sure it will work.
It would look like this
IMyInterface objcls = getconstrorclass() as IMyInterface;
if (objcls != null)
objcls.callclass();
else
// we failed miserably and should do something about it
I don't think you should use some generic object returning constructor based on an int variable, if your classes don't have anything in common. It's really weird to handle it like this and it may lead to various problems (some of which you're currently already experiencing). Generic class constructors make sense if the classes are somewhat related and you can predict the outcome, but to create a do-it-all method.. Not so sure about correctness of such approach.
Anyway, if you insist (not recommended, but as you wish), you can create some checks for a type like this:
var createdObject = getConstructorclass(1);
if (createdObject is MyClass1)
{
var specificObject = (MyClass1)createdObject;
specificObject.callMethod1();
}
else if (createdObject is MyClass2)
{
var specificObject = (MyClass2)createdObject;
specificObject.callSomeOtherMethod();
}
...
But it gets very error prone soon, refactoring will probably be a nightmare etc., but it's your call..
Or you maybe can use solution from pwas, but to me it seems unnecessarily complicated for such a basic task. Looks nice and all, but it still returns only the type "object", so it doesn't really solve your specific problem.
Also, to address one issue I'm not sure you understand - you've already created the instance, you just return type object. That is why you can't call any specific methods on this object, because first you have to cast it to something, that actually has that method and make sure the cast can be done (inheritance etc).
If interface solution (see other answers) is enough, don't look at this answer. When you can't use common base class / interface and you still want call members, you can use solution with is keyword (and check types). Instead of writing many ifs for each case, you can use fluent API:
object obj = this.getConstructorclass();
obj.StronglyInvoke()
.When<int>(value => Console.WriteLine("Got {0} as int", value))
.When<string>(value => Console.WriteLine("Got {0} as string", value))
.OnFail(() => Debug.Write("No handle."))
.Invoke();
Solution:
public class GenericCaller
{
private IList<GenericInvoker> invokers = new List<GenericInvoker>();
private readonly object target;
private Action failAction;
public GenericCaller(object target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
this.target = target;
}
public GenericCaller OnFail(Action fail)
{
this.failAction = fail;
return this;
}
public GenericCaller When<T>(Action<T> then)
{
if (then == null)
{
throw new ArgumentNullException("then");
}
var invoker = new GenericInvoker<T>(this.target, then);
this.invokers.Add(invoker);
return this;
}
public void Invoke()
{
if (this.invokers.Any(invoker => invoker.Invoke()))
{
return;
}
if (this.failAction == null)
{
throw new InvalidOperationException("Handler not found");
}
this.failAction();
}
public abstract class GenericInvoker
{
protected readonly object target;
protected GenericInvoker(object target)
{
this.target = target;
}
public abstract bool Invoke();
}
public class GenericInvoker<T> : GenericInvoker
{
private readonly Action<T> then;
public GenericInvoker(object target, Action<T> then)
: base(target)
{
this.then = then;
}
public override bool Invoke()
{
if (this.target.GetType() == typeof(T))
{
this.then((T)this.target);
return true;
}
return false;
}
}
}
public static class Extensions
{
public static GenericCaller StronglyInvoke(this object o)
{
return new GenericCaller(o);
}
}
Remeber - it would be more elegant to use common interface (as other answers say) - my is only alternative way.
Declare your variable as dynamic
dynamic objcls = getconstrorclass();
Using this the will be determined at run-time, whatever the getconstrorclass method returns. You can access any member of the type and you won't get any error at compile-time. But if you try to access a member which doesn't exists you will get a RuntimeBinderException at runtime.
I would recommend using an interface and restricting the classes that you can instantiate this way to only those that implement the interface.
public interface IMyInterface
{
void callclass();
}
public <T> getConstructorClass()
{
T instance;
Type type = Type.GetType("test1");
// instance will be null if the object cannot be cast to type T.
instance = Activator.CreateInstance(type) as T;
return T;
}
IMyInterface objcls = getConstructorClass<IMyInterface>();
if(null != objcls)
{
objcls.callclass();
}
not sure what you want to achieve in the end, but this looks like a job for "Dependency Injection" - here is a nice sample using autofac

Dilemma in calling constructor of generic class

I have this generic singleton that looks like this:
public class Cache<T>
{
private Dictionary<Guid, T> cachedBlocks;
// Constructors and stuff, to mention this is a singleton
public T GetCache(Guid id)
{
if (!cachedBlocks.ContainsKey(id))
cachedBlocks.Add(id, LoadFromSharePoint(id))
return cachedBlocks[id];
}
public T LoadFromSharePoint(Guid id)
{
return new T(id) // Here is the problem.
}
}
The error message is:
Cannot create an instance of type T because it does not have the new() constraint.
I have to mention that I must pass that id parameter, and there is no other way to do so. Any ideas on how to solve this would be highly appreciated.
Normally you would constrain the type T to a type that has a default constructor and call that. Then you'd have to add a method or property to be able to provide the value of id to the instance.
public static T LoadFromSharePoint<T>(Guid id)
where T : new() // <-- Constrain to types with a default constructor
{
T value = new T();
value.ID = id;
return value;
}
Alternatively since you specify that you have to provide the id parameter through the constructor, you can invoke a parameterized constructor using reflection. You must be sure the type defines the constructor you want to invoke. You cannot constrain the generic type T to types that have a particular constructor other than the default constructor. (E.g. where T : new(Guid) does not work.)
For example, I know there is a constructor new List<string>(int capacity) on List<T>, which can be invoked like this:
var type = typeof(List<String>);
object list = Activator.CreateInstance(type, /* capacity */ 20);
Of course, you might want to do some casting (to T) afterwards.
To do this you should specify what T is. Your Cache<T> can hold anything? Tiger, Fridge and int as well? That is not a sound design. You should constrain it. You need an instance of T which will take a Guid to construct the instance. That's not a generic T. Its a very specific T. Change your code to:
public class Cache<T> where T : Cacheable, new()
{
private Dictionary<Guid, T> cachedBlocks;
// Constructors and stuff, to mention this is a singleton
public T GetCache(Guid id)
{
if (!cachedBlocks.ContainsKey(id))
cachedBlocks.Add(id, LoadFromSharePoint(id))
return cachedBlocks[id];
//you're first checking for presence, and then adding to it
//which does the same checking again, and then returns the
//value of key again which will have to see for it again.
//Instead if its ok you can directly return
//return cachedBlocks[id] = LoadFromSharePoint(id);
//if your LoadFromSharePoint is not that expensive.
//mind you this is little different from your original
//approach as to what it does.
}
public T LoadFromSharePoint(Guid id)
{
return new T { Key = id }; // Here is no more problem.
}
}
public interface Cacheable
{
Guid Key { get; set; }
}
Now derive all the cacheables (whatever Ts that you will pass it for Cache<T>) from the interface Cacheable.
In order to use the constructor of a Generic Type without any constraint, and within the class, the syntax where T : class, new() needs to be used
This enables to change values of attributes (fields) - not only get/set properties) at runtime depending the target class used
First, declaring the generic class:
public class Foo<T> where T : class, new()
{
public T oneEmptyElement()
{
return new T();
}
public T setAttribute(string attributeName, string attributeValue)
{
T objT = new T();
System.Reflection.FieldInfo fld = typeof(T).GetField(attributeName);
if (fld != null)
{
fld.SetValue(objT, attributeValue);
}
return objT;
}
public List<T> listOfTwoEmptyElements()
{
List<T> aList = new List<T>();
aList.Add(new T());
aList.Add(new T());
return aList;
}
}
Declare then a potential target class:
public class Book
{
public int name;
}
And finally the call can be done like this:
Foo<Book> fooObj = new Foo<Book>();
Book aBook = fooObj.oneEmptyElement();
aBook.name = "Emma";
Book anotherBook = fooObj.setAttribute("name", "John");
List<Book> aListOfBooks = fooObj.listOfTwoEmptyElements();
aListOfBooks[0].name = "Mike";
aListOfBooks[1].name = "Angelina";
Console.WriteLine(aBook.name); //Output Emma
Console.WriteLine(anotherBook.name); //Output John
Console.WriteLine(aListOfBooks[0].name); // Output Mike
Console.WriteLine(aListOfBooks[1].name); // Output Angelina

Categories