I have a parent class, with has a property that contain a list of the children class.
//Parent Class :
public class Family
{
private MemberList _familymember = new MemberList();
public MemberList FamilyMember
{
get { return _familymember ; }
set { _familymember = value; }
}
}
//Children Class :
public class Member
{
private string _name;
public string Name
{
get { return _name; }
set { _name= value; }
}
}
public class MemberList : List<Member>
{
}
//And here is how I use them :
Family myFamily = new Family();
Member dad = new Member();
Member mom = new Member();
//I add the children into the parent property :
myFamily.FamilyMember.Add(dad);
myFamily.FamilyMember.Add(mom);
//I have other different similar parent-children classes, eg : School-Classroom, Country-States and etc.
//In one condition, I need to write a generic class to process the List<custom> type property :
//some function that will return a children list object.
object ChildrenList = somefunction();
List<object> ObjectList = (List<object>)ChildrenList;
//and trying to get the Type name inside the List :
Type ChildrenType = ObjectList.GetType().GetGenericArguments()[0];
//It gives me error :
Unable to cast object of type 'MemberList' to type'System.Collections.Generic.List`1[System.Object]'
//or when I process other types of list
Unable to cast object of type 'ClassroomList' to type 'System.Collections.Generic.List`1[System.Object]'
Unable to cast object of type 'StateList' to type 'System.Collections.Generic.List`1[System.Object]'
I am trying to write a general class to process the list, therefore I wouldn't know the type of the list property. Any idea how I can cast them into List ?
All help is appreciated !!
Update & Solution :
Like aevitas suggested, I have changed the list property to use
private List<Member> _familymember = List<Member>();
And then I use the IList interface I found in other topic,
object returnedList = somefunction(); // some function that return a List of object.
IList myList = (IList)returnedList ;
Now the rest of the code works, I can loop through the IList like normal.
Thanks all!
You could add a common interface for all children classes (Member, Classroom & State), otherwise there is absolutely no connection between List<object> and List<MemberType> as this would allow the following:
List<object> myList = (List<object>) memberTypeList;
myList.Add(5); // oops
Also: as unfortunate as it is, there is no type aliasing in C# like there is in C or C++. Still, deriving from a class looks like its a workaround but its semantically wrong and should not be used.
You should never inherit List<T>, instead you should declare one instead:
public class Family
{
private List<Member> _familymember = List<Member>();
public List<Member> FamilyMember
{
get { return _familymember ; }
set { _familymember = value; }
}
}
On top of that, you should never be casting your types down to object, use a common type or interface instead as D.R. suggested.
If you want to stick to your guns, and you want to convert your MemberList object to a List<Member>, you could do it like this:
public static IEnumerable<T> GetList<T>(List<T> source)
{
return source;
}
And call it like this:
var list = GetList<Member>(memberList).ToList();
That should at least solve your compiler errors, but it won't solve the design errors in this one.
Related
How Can I dynamically cast at runtime.That is I am passing a child class object in the parent class object.
public abstract class tObject
{
public tObject[] someMthode(){;}
}
public class myClass : tObject
{
public string Oth0 { get; set; }
public string Oth1 { get; set; }
public string Oth2 { get; set; }
}
I want
myClass mc=new myClass();
tObject to=mc;
myClass[] mcArray=(myClass[])mc.someMthode();//System.InvalidCastException
//Unable to cast object of type 'tObject[]' to type 'myClass[]'
but when check any element of mcArray is correct
if (mcArray[0] is myClass)
{
//return true and run this ;
}
In fact I want cast when a method return array of tObject according to the base class :
subClass[] mcArray=(subClass[])instanceOfsubClass.someMthode()
subClass or myClass and ... are unknown class , and i don't know theirs name.
Solution
public T[] Cast<T>(tObject[] mcArray ) where T : tObject
{
if (mcArray != null)
{
int cnt = mcArray.GetLength(0);
T[] t = new T[cnt];
for (int i = 0; i < cnt; i++)
{
t[i] = (T)mcArray[i];
}
return t;
}
return null;
}
Thanks all for replies.
C# does not support that kind of array conversion. C# does -- unfortunately! -- support dangerous array covariance. That is, if you had an array myClass[] then you could implicitly convert it to an array tObject[]. This means that you can do this:
Tiger[] tigers = new Tiger[10];
Animal[] animals = tigers;
animals[0] = new Turtle();
and now we have a turtle inside an array of tigers. This crashes at runtime.
That's bad enough, but you want it to go the other way -- I have an array of animals and I'd like it to be treated as an array of tigers. That does not work in C#.
As other answers have noted, you'll need to make a second array and copy the contents of the first to the second. There are a number of helper methods to do so.
Maybe?
myClass mc = new myClass();
tObject to = mc;
//myClass[] mcArray = (myClass[])mc.someMthode();//System.InvalidCastException
//Unable to cast object of type 'tObject[]' to type 'myClass[]'
var mcArray = Array.ConvertAll(mc.someMthode(), item => (myClass) item);
Well, you can call IEnumerable.Cast for that:
var myArr = mc.someMethod().Cast<MyClass>().ToArray();
As MyClass[] implements IEnumerable<MyClass>.
EDIT: What you want is quite dangerous. Look the following code:
subClass[] mcArray=(subClass[]) new BaseClass[] {...};
If this conversion would work we could now simply make the following also:
mcArray[0] = new AnotherClass();
Now you have an array of subClasses containin one item of AnotherClass also.
If you do not know the type at compile-time you cannot expect the compiler to provide any compile-time-logic for a type it doesn´t know. Thus casting to an unknown type and calling members on isn´t supported. However you may achieve this using reflection:
var runtimeType = myArr[0].GetType();
var mi = runtimeType.GetMethod("SomeMethod");
var value = mi.Invoke(myArr[0]);
This is similar to the call
var value = ((subClass)myArr[0]).SomeMethod();
Why not solve it one step up the chain and make someMethod (spelling corrected) generic:
public abstract class tObject<T> where T:tObject
{
public T[] someMethod(){;}
}
public class myClass : tObject<myClass>
{
public string Oth0 { get; set; }
public string Oth1 { get; set; }
public string Oth2 { get; set; }
}
now myClass.someMethod returns a myclass[] and that problem is solved. However, since I'm assuming that tObject does other things that just create an array of tObjects, it may cause other problems that aren't inferrable from the code you provided.
Plus it's not 100% foolproof. There's nothing stopping you (or someone else) from defining:
public class myWeirdClass : tObject<myClass>
{
}
now myWeirdClass.someMethod also returns a myClass[], and the pattern is broken. Unfortunately there's no generic constraint that requires that the generic parameter be the defining class itself, so there's no way to prevent this flaw at compile-time.
Another option may be to move the array creation outside of the class itself, since it is a code smell in itself:
public class ObjectFactory<T> where T:tObject
{
public T[] SomeMethod()
{
... create an array of Ts
}
}
So I have an Object called FormType.
It contains some strings, booleans etc.
But FormType also contains this:
private IList<FormTypeVersion> _versions = new List<FormTypeVersion>();
public virtual IList<FormTypeVersion> Versions
{
get { return _versions; }
set { _versions = value; }
}
Is this why I am getting this error:
{"Cannot serialize member 'Domain.FormType.Versions' of type 'System.Collections.Generic.IList`1
Also - FormTypeVersion also contains some ILists.
How can I get round this error, it happens at this line:
var xm = new XmlSerializer(typeof(T));
The XmlSerializer cannot deserialize interfaces (unless you want to implement IXmlSerializable yourself on the FormType object). That is why you are seeing that exception.
If you change your IList to List it should work like in the following example:
[Serializable]
public class FormType
{
private List<FormTypeVersion> _versions = new List<FormTypeVersion>();
public virtual List<FormTypeVersion> Versions
{
get { return _versions; }
set { _versions = value; }
}
}
If you don't have the luxury to change your type from IList to List, then the cleanest approach is to implement IXmlSerializable. There are other solutions using abstract types, reflection and similar, but i wouldn't call that clean.
Hi I have a simple issue with an sql application that I seem not to be capable of resolve. It involves the use of generics of which I am not too familiar with. I did researches here and on-line but I do not seem to find a fitting solution for my case.
I have two classes: Table and Field. I want Table to contain a List of Field and I want each Field to contain a List of RecordSet. The tricky part is that I want the user to choose which type of RecordSet to implement.
The Class Definition of Table is:
namespace DBlib
{
public class DBTable<T>
{
public List<DBField<T>> FieldName = new List<DBField<T>>();
public DBTable (string NameOfTable)
{
}
public void AddField (string Name)
{
DBField<T> TempList = new DBField<T>();
FieldName.Add(TempList);
}
}
}
The Class Definition of Field is:
namespace DBlib
{
public class DBField<T>
{
public List<T> RecordSet = new List<T>();
public DBField()
{
}
}
}
With this code the user is forced cast the type when he is instantiating DBTable. This is not correct. I want the user to cast the type when the AddField method is invoked. Can you suggest a simple way to solve this issue?
UPDATE #1
I changed TempList as DBField in the Table Class definition. Sorry for the confusion there.
I want to add also this code to explain better what my issue is. Assuming the first Field of the table is an integer, the user should do:
namespace SpecifytheName
{
public class User
{
DBTable<int> Table = new DBTable<int>();
public User()
{
}
}
}
Instead, I want the user to do:
namespace SpecifytheName
{
public class User
{
DBTable Table1 = new DBTable("Table1");
// SPECIFY THE TYPE OF FIELD1 ONLY AT THIS POINT
Table1.AddField<int>("Field1"); //or something like this
public User()
{
}
}
}
I would generally solve this issue using a non-generic interface to store your fields.
So start with this interface:
public interface IDBField
{
IList RecordSet { get; }
Type FieldType { get; }
}
Now implement DBField<T> like this:
public class DBField<T> : IDBField
{
public List<T> RecordSet = new List<T>();
IList IDBField.RecordSet
{
get
{
return this.RecordSet;
}
}
Type IDBField.FieldType
{
get
{
return typeof(T);
}
}
}
Then you can implement DBTable like this:
public class DBTable
{
public List<IDBField> FieldName = new List<IDBField>();
public void AddField<F>(string Name)
{
FieldName.Add(new DBField<F>());
}
}
You can use the FieldType property on IDBField to determine the type of the field and then use reflection as necessary to use the values of RecordSet appropriately.
The only way I can see this working is by not using Generics, but just use the Object class.
for example:
public class DBTable
{
public List<DBField<Object>> FieldName = new List<DBField<Object>>();
public DBTable (string NameOfTable)
{
}
public void AddField(string Name)
{
List<DBField<Object>> TempList = new List<DBField<Object>>();
FieldName.Add(TempList);
}
}
This will mean you can use any type in the RecordSet object without restricting the type in the DBTable class.
I could be a bit off base here as I'm not sure what you're trying to achieve, for one you aren't going anything with the Name parameter passed into the AddField method, and you're TempList object isn't the same type as FieldName so it should throw some errors there..
EDIT:
I think I understand more clearly what you're trying to do, try this -
public class DBTable
{
public List<DBField<Object>> FieldName = new List<DBField<Object>>();
public DBTable (string NameOfTable)
{
}
public void AddField<FieldType>(string Name)
{
DBField<FieldType> field = new DBField<FieldType>(Name);
FieldName.Add(field);
}
}
This way each Field (Column) is still forced to a type, but the DBTable isn't tied down to that same type.
I'm trying to figure out how I can make a Generics call take a variable for the Type. In the call below it take a type "DAL.Account" and works fine.
var tst = ctx.GetTable<DAL.Account>().Where(t => t.Sbank == "000134");
I want to change that so that I can pass a variable in place of the "DAL.Account". Something like this but I know that won't work as you can't pass property as a Type.
ctx.GetTable<Criteria.EntityType>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray())
Below is the shell pieces of code I think explains what I'm trying to do. Generics is not my strong suit so I'm looking for some help. Is there anyway that I can make this happen?
//Stores a "Type" that indicates what Object is a Criteria for.
public class AccountCriteria : IGeneratedCriteria
{
...
public Type EntityType
{
get {return typeof(DAL.Account);}
}
}
//I have added a function to the DataContext called "GetTable"
// And then used it as an example in a Console App to test its functionality.
public class ADRPDataContext : NHibernateDataContext
{
...
public CodeSmith.Data.NHibernate.ITable<T> GetTable<T>() where T : EntityBase
{
var tb = new CodeSmith.Data.NHibernate.Table<T>(this);
return tb;
}
}
// console application that uses DataContext.GetTable
class Program
{
static void Main(string[] args)
{
using (var ctx = new ADRPDataContext())
{
var tst = ctx.GetTable<DAL.Account>().Where(t => t.Sbank == "000134");
}
}
}
//ExistsCommand class that uses the EntityType property of the Critera to generate the data.
public class ExistsCommand
{
private IGeneratedCriteria Criteria { get; set; }
protected override void DataPortal_Execute()
{
using (var ctx = new DC.ADRPDataContext())
{
//This was my first attempt but doesn't work becuase you can't pass a property in for a Type.
//But I can figure out how to write this so that it will work.
Result = ctx.GetTable<Criteria.EntityType>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray()).Count() > 0;
}
}
}
You are looking to instantiate a generic type. Some info can be found here
This is a simple example demonstrating how to instantiate a List with a capacity of 3. Here is a method that you can call to create a generic when you don't know the type:
public static Object CreateGenericListOfType(Type typeGenericWillBe)
{
//alternative to the followin:
//List<String> myList = new List<String>(3);
//build parameters for the generic's constructor (obviously this code wouldn't work if you had different constructors for each potential type)
object[] constructorArgs = new Object[1];
constructorArgs[0] = 3;
//instantiate the generic. Same as calling the one line example (commented out) above. Results in a List<String> with 3 list items
Type genericListType = typeof(List<>);
Type[] typeArgs = { typeGenericWillBe };
Type myNewGeneric = genericListType.MakeGenericType(typeArgs);
object GenericOfType = Activator.CreateInstance(myNewGeneric, constructorArgs);
return GenericOfType;
}
And here is some sample code that will show you the example method works:
List<String> Strings = (List<String>)InstantiateGenericTypeWithReflection.CreateGenericListOfType(typeof(String));
//demonstrate the object is actually a List<String> and we can do stuff like use linq extensions (isn't a good use of linq but serves as example)
Strings.Add("frist");
Strings.Add("2nd");
Strings.Add("tird");
Console.WriteLine("item index 2 value: " + Strings.Where(strings => strings == "2").First());
In your example, replace your GetTable<Criteria.EntityType>() with CreateGenericTableOfType(Criteria.EntityType). This will return a generic table of whatever type you pass in. You will of course need to implement the method properly (handle constructor args, change List to Table etc).
I think you need to change the way you're doing this slightly, and instead use generics instead of the EntityType property. Perhaps something along the lines of the following:
// Create an abstract class to be used as the base for classes that are supported by
// ExistsCommand and any other classes where you need a similar pattern
public abstract class ExtendedCriteria<T> : IGeneratedCriteria
{
public ExistsCommand GetExistsCommand()
{
return new ExistsCommand<T>(this);
}
}
// Make the non-generic ExistsCommand abstract
public abstract class ExistsCommand
{
protected abstract void DataPortal_Execute();
}
// Create a generic sub-class of ExistsCommand with the type parameter used in the GetTable call
// where you were previously trying to use the EntityType property
public class ExistsCommand<T> : ExistsCommand
{
protected override void DataPortal_Execute()
{
using (var ctx = new DC.ADRPDataContext())
{
Result = ctx.GetTable<T>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray()).Count() > 0;
}
}
}
// Derive the AccountCriteria from ExtendedCriteria<T> with T the entity type
public class AccountCriteria : ExtendedCriteria<DAL.Account>
{
...
}
I have a set of custom data types that can be used to manipulate basic blocks of data. For example:
MyTypeA Foo = new MyTypeA();
Foo.ParseString(InputString);
if (Foo.Value > 4) return;
Some of these types define read-only properties that describe aspects of the types (for example a name, bit size, etc.).
In my custom framework I want to be able to provide these types to the user for use in their applications but I also want to give the user a list of the available types which they could easily bind to a combobox. My current approach:
public static class DataTypes
{
static ReadOnlyCollection<MyDataType> AvailableTypes;
static DataTypes()
{
List<MyDataType> Types = new List<MyDataType>();
Types.Add(new MyTypeA());
Types.Add(new MyTypeB());
AvailableTypes = new ReadOnlyCollection<MyDataType>(Types);
}
}
What concerns me about this is that the user might obtain a type from the AvailableTypes list (by selecting a combobox item for example) and then use that reference directly rather than creating a clone of the type and using their own reference.
How can I make the list of available types read only so that it doesn't allow any writing or changes to the type instances, forcing the user to create their own clone?
Alternatively is there a better way of providing a list of available types?
Thanks, Andy
Make your custom Type class immutable, same as System.Type and you dont have to worry. A end user can fetch all the data it wants but he can not modify the object in any way.
EDIT: Example of immutable class
Take the following class for instance:
public class ImmutablePerson
{
private readonly string name; //readonly ensures the field can only be set in the object's constructor(s).
private readonly int age;
public ImmutablePerson(string name, int age)
{
this.name = name;
this.age = age;
}
public int Age { get { return this.age; } } //no setter
public string Name { get { return this.name; } }
public ImmutablePerson GrowUp(int years)
{
return new ImmutablePerson(this.name, this.age + years); //does not modify object state, it returns a new object with the new state.
}
}
ImmutablePerson is an immutable class. Once created there is no way a consumer can modify it in any way. Notice that the GrowUp(int years) method does not modify the state of the object at all, it just returns a new instance of ImmutablePerson with the new values.
I hope this helps you understand immutable objects a little better and how they can help you in your particular case.
To get around the problems you've mentioned, you could create a wrapper around your instances, and have the wrapper provide the functionality you require.
For example:
public class TypeDescriptor
{
private MyDataType _dataType;
public TypeDescriptor(MyDataType dataType)
{
_dataType = dataType;
}
public override string ToString()
{
return _dataType.ToString();
}
}
You class would then look something like:
public static class DataTypes
{
public static ReadOnlyCollection<TypeDescriptor> AvailableTypes;
static DataTypes()
{
List<TypeDescriptor> Types = new List<TypeDescriptor>();
Types.Add(new TypeDescriptor(new MyTypeA()));
Types.Add(new TypeDescriptor(new MyTypeB()));
AvailableTypes = new ReadOnlyCollection<TypeDescriptor>(Types);
}
}
Binding to the list and relying on the ToString() will now result in your data types ToString being called.
Create a list of types rather than a list of instances. e.g.
List<Type> Types = new List<Type>();
Types.Add(typeof(MyTypeA));
Types.Add(typeof(MyTypeB()));
etc.
To answer the comment on binding to a drop down list:
MyDropDown.Datasource = Type.Select(t => t.Name);
MyDropDown.DataBind();
This will not use the custom property of your classes but it will give you the simple calss name without all the other guff e.g. MyTypeA
A collection cannot "inject" type modifiers into its members. The collection you have declared is readonly. If you want MyDataType to be readonly you must declare that way.
Somthing like :
EDIT extended class to have a parse method
public class MyDataType
{
private MyDataType()
{
...
}
internal static MyDataType Parse(string someString)
{
MyDataType newOne = new MyDataType();
newOne.Value = ... //int.Parse(someString); ?
}
public int Value { get; private set; }
}
If the collection stays generic there is no readonly constraint.
You would use it like this, following your example.
MyTypeA foo = MyTypeA.Parse(inputString);
if (foo.Value > 4) return;
You probably shouldn't store instances of your types in the list. Instead you can store types. These can be used to create instances:
public static class DataTypes
{
static ReadOnlyCollection<Type> AvailableTypes;
static DataTypes()
{
List<Type> Types = new List<Type>();
Types.Add(typeof(MyTypeA));
Types.Add(typeof(MyTypeB));
AvailableTypes = new ReadOnlyCollection<MyDataType>(Type);
}
}
You can use Activator.CreateInstance to create a concrete instance:
Object myType = Activator.CreateInstance(AvailableTypes[0]);
Unless your types share a common base type you cannot downcast the result and an Object isn't that useful.
Also the use of the term type in your code makes my example a bit confusing as I suggest you store the types of something called type.
You could consider creating and attribute that you then can apply to MyTypeA, MyTypeB etc. Then you can build the AvailableTypes using reflection and the list will always be up to date with your code. E.g. if you add MyTypeC and use the attribute it will automatically be added to the list.
You can also add a display string property to the attribute and use that for display in the combo box. If you want to do that you should store a small object combining the type and the display string in AvailableTypes.
Here is an example. Using generic words like type and data can be confusing so to pick a random name I just use foo. Obviously you should use a more descriptive name.
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
sealed class FooAttribute : Attribute {
public FooAttribute(String displayName) {
DisplayName = displayName;
}
public String DisplayName { get; private set; }
}
You can decorate you classes using this attribute:
[Foo("Type A")]
class MyTypeA { ... }
[Foo("Type B")]
class MyTypeB { ... }
For the combobox you want a list of factory objects with a nice ToString implementation (this class can be improved by adding some error handling which I have left out to save space):
class FooFactory {
readonly Type type;
public FooFactory(Type type) {
this.type = type;
DisplayName = ((FooAttribute) Attribute.GetCustomAttribute(
type,
typeof(FooAttribute))
).DisplayName;
}
public String DisplayName { get; private set; }
public Object CreateFoo() {
return Activator.CreateInstance(this.type);
}
public override String ToString() {
return DisplayName;
}
}
Returning Object from CreateFoo isn't very useful but that is a separate issue.
You can build this list at run-time:
var factories = Assembly
.GetExecutingAssembly()
.GetTypes()
.Where(t => Attribute.IsDefined(t, typeof(FooAttribute)))
.Select(t => new FooFactory(t));
I'm not exactly sure of what you want but should something like this be ok ?
public static class DataTypes
{
static Dictionary<string,Type> AvailableTypes
= new Dictionary<string,Type>()
{
{ "MyTypeA", MyTypeA },
{ "MyTypeB", MyTypeB },
...
};
}
That is actually return types instead of sample instances of theses types. Thus you would be sure that only new instances would be created by the user of your class.
Then in the calling code :
MyTypeA a = Activator.CreateInstance(DataTypes.AvailableTypes["MyTypeA"]);