I have an interface defined as:
public interface MyInterface {
object foo { get; set; };
}
and a class that implements that interface:
public class MyClass : MyInterface {
object foo { get; set; }
}
I then create a function that returns a ICollection like so:
public ICollection<MyClass> Classes() {
List<MyClass> value;
List<MyInterface> list = new List<MyInterface>(
new MyInterface[] {
new MyClass {
ID = 1
},
new MyClass {
ID = 1
},
new MyClass {
ID = 1
}
});
value = new List<MyClass>((IEnumerable<MyClass>) list);
return value;
}
It would compile but would throw a
Unable to cast object of type
'System.Collections.Generic.List1[MyInterface]'
to type
'System.Collections.Generic.IEnumerable1[MyClass]'.
exception. What am I doing wrong?
A List<MyInterface> cannot be converted to a List<MyClass> in general, because the first list might contain objects that implement MyInterface but which aren't actually objects of type MyClass.
However, since in your case you know how you constructed the list and can be sure that it contains only MyClass objects, you can do this using Linq:
return list.ConvertAll(o => (MyClass)o);
But a List<MyInterface> is emphatically not a List<MyClass>.
Think:
interface IAnimal { }
class Cat : IAnimal { }
class Dog : IAnimal { }
var list = new List<IAnimal> { new Cat(), new Dog() };
Then
var cats = (List<Cat>)list;
Absurd!
Also,
var cats = list.Cast<Cat>();
Absurd!
Further
var cats = list.ConvertAll(x => (Cat)x);
Absurd!
Instead, you could say
var cats = list.OfType<Cat>();
You could use Cast<> extension method:
return list.Cast<MyClass>();
I find Automapper very useful for converting interfaces to concrete classes.
It is possible and that's where the generics shine!
Here is a simple example:
public interface ICountable
{
int Count { get; set; }
}
public class PopularName : ICountable
{
public string Name { get; set; }
public int Count { get; set; }
}
public class PopularSize : ICountable
{
public int Size { get; set; }
public int Count { get; set; }
}
And now you need to declare your method (or your class) generic like this:
public bool HasAnyValue<T>(List<T> countableModel) where T : ICountable
{
return countableModel.Count > 0;
}
Related
I have 2 classes:
public class GenericClass<T>
{
public T Item {get;set;}
}
public class StringClass
{
public string Item {get;set;}
}
now i have a GenericClass object and i need to cast it to StringClass object:
var genericObj = new GenericClass<string>();
var stringObj = (StringClass)genericObj; // <---
How to cast / convert from generic class to specific one?
You can't cast one type to the other because the types are unrelated.
You could, however, define a conversion operator:
public class StringClass
{
public string Item { get; set; }
public static explicit operator StringClass(GenericClass<string> generic)
=> new StringClass { Item = generic.Item };
}
Which would allow this syntax:
var genericObj = new GenericClass<string>();
var stringObj = (StringClass)genericObj;
You can't. You would need common inherited type or implement an interface.
With inheritance:
public class GenericClass<T>
{
public T Item {get;set;}
}
public class StringClass : GenericClass<string>
{
}
if your really need it, you can do this way for examle
var stringObj = new StringClass(genericObj);
public class StringClass
{
public string Item { get; set; }
public StringClass(GenericClass<string> genericClass)
{
Item=genericClass.Item;
}
public StringClass(){}
}
or this is more flexible
public interface IGenericClass<T>
{
public T Item { get; set; }
}
public class GenericClass<T>:IGenericClass<T>
{
public T Item { get; set; }
}
public class StringClass
{
public string Item { get; set; }
public StringClass(IGenericClass<string> genericClass)
{
Item=genericClass.Item;
}
public StringClass(){}
}
Using this answer:
var genericObj = new GenericClass<string>();
var stringObj = (StringClass)Convert.ChangeType(genericObj, typeof(StringClass));
Finally i solved using ICloneable,
Here i have a base class named GenericClass, a generic class named GenericClassT, and a class named StringClass.
Inheritance is:
GenericClass <- GenericClassT <- StringClass
Using ICloneable implementation on GenericClass and GenericClassT, adding a CreateObject and CopyTo methods i reach the final goal:
var genericObj = new GenericClass<string>();
var stringObj = (StringClass)genericObj.Clone<StringClass>();
class definitions:
public class GenericClass: ICloneable
{
public string Id {get;set;}
protected virtual ApiRequestResult CreateObject()
{
return new GenericClass();
}
protected virtual void CopyTo(GenericClass obj)
{
obj.Id = Id;
}
public virtual object Clone()
{
var obj = CreateObject();
CopyTo(obj);
return obj;
}
public virtual object Clone<T>() where T: GenericClass
{
var obj = (GenericClass)Activator.CreateInstance(typeof(T));
CopyTo(obj);
return obj;
}
}
public class GenericClass<T>: GenericClass
{
public T Data {get; set;}
protected override GenericClass CreateObject()
{
return new GenericClass<T>();
}
protected override void CopyTo(GenericClass obj)
{
base.CopyTo(obj);
((GenericClass<T>)obj).Data = Data;
}
}
public class StringClass: GenericClass<string>
{
}
I have many similar classes and I am trying to create a generic method that loads a list of objects of each class. I am not using any ORM, but just loading a SqlDataReader with the respective SQL Query.
I have tried using an interface and using generics.
I have simplified the problem below using only 2 short classes:
Interface:
public interface IMyEntity<T> where T : new()
{
public List<T> ConvertToObjects(SqlDataReader dr);
public static IMyEntity<T> CreateInstance()
{
return null;
}
}
Class 1:
public class Cat : IMyEntity<Cat>
{
public long CatID { get; set; }
public string CatName { get; set; }
public int OwnerID { get; set; }
public List<Cat> ConvertToObjects(SqlDataReader dr)
{
List<Cat> cats = new();
if (dr.HasRows)
{
while (dr.Read())
{
Cat cat = new()
{
CatID = dr.GetInt32("CatID"),
CatName = dr.GetString("CatName"),
OwnerID = dr.GetInt32("OwnerID")
};
cats.Add(cat);
}
dr.Close();
}
return cats;
}
public IMyEntity<Cat> CreateInstance()
{
IMyEntity<Cat> cat = new Cat();
return cat;
}
}
Class 2:
public class Dog : IMyEntity<Dog>
{
public long DogID { get; set; }
public string DogName { get; set; }
public int Age { get; set; }
public List<Dog> ConvertToObjects(SqlDataReader dr)
{
List<Dog> dogs = new();
if (dr.HasRows)
{
while (dr.Read())
{
Dog dog = new()
{
DogID = dr.GetInt32("DogID"),
DogName = dr.GetString("DogName"),
OwnerID = dr.GetInt32("Age")
};
dogs.Add(dog);
}
dr.Close();
}
return dogs;
}
public IMyEntity<Dog> CreateInstance()
{
IMyEntity<Dog> dog = new Dog();
return dog;
}
}
And I have another class with this method:
public async Task<IEnumerable<T>> GetObjectAsync<T>(string procedureName)
{
if (_connection.State != ConnectionState.Open) _connection.Open();
SqlCommand command = new(procedureName, _connection);
SqlDataReader dr = await cmd.ExecuteReaderAsync().ConfigureAwait(false);
var myEntity = IMyEntity<T>.CreateInstance();
IEnumerable<T> objs = myEntity.ConvertToObjects(dr);
return objs;
}
The line with 'CreateInstance' is returning the following error: "'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'IMyEntity'"
The T : new() constraint is missing in the calling method’s own generic type.
public async Task<IEnumerable<T>> GetObjectAsync<T>(string procedureName)
Thus the compiler cannot guarantee the constraint requirement for the interface in IMyEntity<T> is met. It is not related to any specific method call and the restriction requirement comes from the interface definition itself.
public interface IMyEntity<T> where T : new()
Either remove the restriction from the interface — in which case new T() cannot be used — or add the restriction to the calling method’s generic type.
Suppose I have two classes and both contain the same fields
Class A
{
public string Name { get; set; }
public int Designaton { get; set; }
}
Class B
{
public string Name { get; set; }
public int Designation { get; set; }
}
And I have one interface and two classes which are inherited from interface
public interface IDeprt
{
object BindData();
}
And two extractor classes:
public classAItem : IDeprt
{
public object BindData()
{
return new A()
{
// mapping operation
}
}
}
public classBItem : IDeprt
{
public object BindData()
{
return new B()
{
//same mapping operation
}
}
}
My question, how can I implement this in generic way using <T> .
Both classes are doing same operation only return type change. If I am doing in the above way there is lot of duplication of code.
Make your ITem interface and also BindData generic make them use the same generic parameter.
public interface IItem<T>
{
T BindData();
}
Then implement the subclasses like below :
public class AItem : ITem<A>
{
public A BindData(){
return new A(){
// mapping operation
}
}
}
public class BItem : ITem<B>
{
public B BindData(){
return new B(){
//same mapping operation
}
}
}
Edit : As the question evolves.
Make a shared base class for A and B classes.
public abstract class CommonItem
{
public string Name { get; set; }
public int Designaton { get; set; }
}
class A : CommonItem
{
}
class B : CommonItem
{
}
Then make class with a method that accepts a generic parameter with new and CommonItem constraints.
public class Binder
{
public T BindData<T>() where T: CommonItem, new()
{
return new T()
{
// you can access the properties defined in ICommonItem
}
}
}
Usage :
var binder = new Binder();
var boundA = binder.BindData<A>();
var boundB = binder.BindData<B>();
I have an Interface and it is implemented by many classes. Each class also has its own set of properties which are not present in interface. Now, if I want to design a factory which returns of type interface, I cannot set some of the derived class properties as they are not member of interface.
How to address this scenario?
If you have an Interface like
public interface MyInterface
{
string Name { get; }
}
and implementations like
public class MyClass : MyInterface
{
string Name { get; set; }
int Something { get; set; }
}
public class MySecondClass : MyInterface
{
string Name { get; set; }
decimal SomethingElse { get; set; }
}
you can create your class in the factory like
public class MyFactory
{
public MyInterface createMyClass()
{
return new MyClass() { Name = "foo", Something = 42 };
}
public MyInterface createMySecondClass()
{
return new MySecondClass() { Name = "bar", SomethingElse = 4.2M };
}
}
Of course this way you can't access the members you don't have declared in your interface.
var something = myFactory.createMyClass().Something;
This wouldn't work. You can only access the name property:
var name = myFactory.createMyClass().Name;
If you would want to access the special property of your class, you would have to cast your interface to the actual class:
var something = ((MyClass)myFactory.createMyClass()).Something;
RootObject.cs
public class RootObject
{
public Class1 Class1 { get; set; }
public Class2 Class2 { get; set; }
public Class3 Class3 { get; set; }
}
Class1.cs (Class2, Class3, ....)
public class Class1
{
public string name { get; set; }
public string surname { get; set; }
}
Enum.cs
public enum Classes
{
Class1,
Class2,
Class3
}
MyFunction.cs
nItemCount = Enum.GetNames(typeof(Classes)).Length; /* equal to 3 */
for (i=0 ; i < nItemCount; i++)
{
string name = RootObject.(Enum.GetName(typeof(Classes), i)).name;
}
I want to get the name value of Class1, Class2, Class3, etc. like a method above.
I wish I could explain my problem.
I need a solution for accessing all classes in a loop with the enum value.
Can anyone please help ?
You will have to change your code to be like below. Note I have used Classes as datatype for the Property.
public class RootObject
{
public Classes ClassProp { get; set; }
}
public enum Classes
{
Class1,
Class2,
Class3
}
And then you can access the properties by using following code. You will have to instantiate the class and then access the property as they are Object level properoties and not static. Also, note that you will have to set the properties to get the appropriate enum value.
RootObject rootObj = new RootObject();
rootObj.ClassProp = Classes.Class2;
var class2 = rootObj.ClassProp;
If your classes share common members, either move those to a common base class or let the classes implement a common interface (or both).
public abstract class Person
{
public string Name { get; set; }
public string Surname { get; set; }
}
public class Customer : Person
{
public Address DeliveryAddress { get; set; }
}
public class Employee : Person
{
public string Profession { get; set; }
}
Then, instead of creating individual properties for each the classes, add them to an array and use the enum values as index:
public enum PersonType
{
Customer = 0,
Employee = 1,
Supplier = 2
}
public class RootObject
{
Person[] _persons = new Person[] {
new Customer(),
new Employee(),
new Supplier()
};
public Person[] Persons { get { return _persons; } }
}
Now you can access the persons easily with
foreach (PersonType personType in (PersonType[])Enum.GetValues(typeof(PersonType))) {
Person p = rootObject.Persons[(int)personType];
string name = p.Name;
string surname = p.Surname;
// ...
}
First, if all of your types Class1, Class2, Class3, ..., ClassWhatNot share same property definitions, it is better to move these same property definitions into a common BaseClass which the aforementioned classes will inherit from.
class BaseClass
{
public string Name { get; set;}
}
class Class1 : BaseClass
{
...
}
class Class2 : BaseClass
{
...
}
//... do the definition of Class3 in the same way
Implement the RootClass as follows (note that i changed the names a bit to make it clearer how things work):
class RootClass
{
public enum PropertyEnum
{
propClass1,
propClass2,
propClass3
}
public Class1 propClass1 { get; set; }
public Class2 propClass2 { get; set; }
public Class3 propClass3 { get; set; }
public BaseClass GetPropertyByEnum(RootClass.PropertyEnum enumValue)
{
PropertyInfo pi = typeof(RootClass).GetProperty(enumValue.ToString());
return pi.GetValue(instance, null) as BaseClass;
}
}
With the method GetPropertyByEnum you can easily do:
RootClass rootObj = ...create/get the root object
foreach(RootClass.PropertyEnum enumValue in Enum.GetValues(typeof(RootClass.PropertyEnum))
{
BaseClass b = rootObj.GetPropertyByEnum(enumValue);
if (b != null) Console.Out.WriteLine("{0}.name = {1}", enumValue.ToString(), b.Name);
}
Note, that when not using a common base class (such as BaseClass in my example), GetPropertyByName could only return references of type Object. In such a case you would need to know how to cast the returned object to the appropriate type, which would make the whole endeavour of accessing properties by enum mostly pointless...