List of Class with Property of T - c#

I am trying to create a list of a class with the property with T:
class Test<T> where T : IClass, new()
{
public T Actor { get { return new T(); } }
public eEnum { get; set; }
public String Str { get; set; }
}
The above is an example class, how can I create a list of the above class?
I have tried the below with no avail:
List<Test<IClass>> list = new List<IClass>();
Is there a way to achieve creating a list like I am trying to generate?

Since you have added the generic type constraint new(), you must provide a type that has a public parameterless constructor. An interface doesn't have a constructor. Therefore you must indicate a class. E.g.
List<Test<MyActorClass>> list = new List<Test<MyActorClass>>();
Or drop this new() constraint and instead add a generic factory method
class Test
{
public T CreateActor<T>()
where T : IClass, new()
{
return new T();
}
public MyEnum eEnum { get; set; }
public string Str { get; set; }
}
And simply create a list List<Test>.
Or supply a concrete actor type through constructor injection:
class Test
{
public Test(IClass actor)
{
Actor = actor;
}
public IClass Actor { get; }
public MyEnum eEnum { get; set; }
public string Str { get; set; }
}
An even more advanced construction is to use a non-generic abstract base class and to derive a generic one from it
abstract class Test
{
private IClass _actor;
public IClass Actor
{
get {
if (_actor == null) {
_actor = CreateActor();
}
return _actor;
}
}
public MyEnum eEnum { get; set; }
public string Str { get; set; }
protected abstract IClass CreateActor(); // We implement it in the generic class.
}
class Test<T> : Test
where T : IClass, new()
{
public new T Actor // Hides inherited member.
{
get { return (T)base.Actor; }
}
protected override IClass CreateActor()
{
return new T();
}
}
The list would again be of type List<Test>. This has the advantage that you can add different types of classes deriving from Test to the list and at the same time you have a strongly typed actor when accessing it through a concrete Test<T>.

Related

Generics: cast derived class back to it's parent super class

I have three base classes:
public class ItemBase
{
public string Name { get; set; }
}
public class ProductBase<T> : ItemBase
where T : ItemBase
{
public List<T> Modifiers { get; set; }
public List<T> GroupModifiers { get; set; }
}
public class ModifierBase<T> : ItemBase
where T : ItemBase
{
public List<T> ChildModifiers { get; set; }
}
And two derived classes:
public class Product : ProductBase<Modifier>
{
public string Some_Product_Specific_Property { get; set; }
}
public class Modifier : ModifierBase<Modifier>
{
public string Some_Modifier_Specific_Property { get; set; }
}
The intent behind all this is to have different sets of derived classes like Product and ProductFromOtherSystem each with it's own specific properties but with the same basic properties.
And now I need to process basic properties of any class derived from ProductBase<T>.
For this purpose I want to use something like this:
public static void DoSomething(ProductBase<ModifierBase<ItemBase>> item)
{
Console.WriteLine(item.Name);
}
The issue here is that I cannot pass parameters to it:
Product product1 = new Product();
DoSomething(product1);
ProductFromOtherSystem product2 = new ProductFromOtherSystem();
DoSomething(product2 as ProductBase<ModifierBase<ItemBase>>);
The error is like
Cannot convert type _ to _ via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion
I've tried to downcast it somehow but have not found any solution. I wonder if it is possible to do it?

Why can't we set a derived type for generic parameters?

In the below code
public class CustomValidator<T>
{
// some code
}
public abstract class Parent
{
public CustomValidator<Parent> Validator { get; protected set; }
}
public class Child : Parent
{
public string Name { get; set; }
public Child()
{
Validator = new CustomValidator<Child>();
// Doesn't work, cannot cast implicitly
}
}
Since we can assign child to a parent,
why can't we set CustomValidator<Child> for a property of type CustomValidator<Parent>?
You can try to leverage covariance in C# introducing covariant interface, if your code allows it:
public interface ICustomValidator<out T> // Your new interface
{
// some code
}
public class CustomValidator< T>:ICustomValidator<T>
{
// some code
}
public abstract class Parent
{
// Change property to your new interface
public ICustomValidator<Parent> Validator { get; protected set; }
}
public class Child : Parent
{
public string Name { get; set; }
public Child()
{
Validator = new CustomValidator<Child>();
}
}
If you can't make your ICustomValidator interface(via marking the generic parameter with out keyword) covariant then as #Michael Randall said in comments
CustomValidator<Parent> != CustomValidator<Child>

How would one handle different return types when overriding abstract method

Say I have the following classes:
public abstract class A
{
protected abstract ReturnA Foo();
public void UseFoo()
{
var foo = Foo();
if (foo != null)
{
//logic here
}
}
}
public class B : A
{
protected override ReturnA Foo()
{
// Implementation specific code that returns ReturnB instead.
}
}
public class C : A
{
protected override ReturnA Foo()
{
// Implementation specific code that returns ReturnC instead.
}
}
public class ReturnA
{
public int Id { get; set; }
public string Address { get; set; }
}
public class ReturnB
{
public string Id { get; set; }
public string PhoneNumber { get; set; }
}
public class ReturnC
{
public Guid Id { get; set; }
public string Name { get; set; }
}
I know that C# does not support derived return types, but this is not what I need either.
Classes B and C are implementation specific and therefore their return types have nothing to do with eachother.
The reason why I would want to handle this, is because the method UseFoo in class A may have some generic checks and other generic logic, that has nothing to do with the returned object itself.
So I want to "outsource" only the code that is implementation specific and not have to instead make UseFoo abstract and have every implementation write the same generic code.
Is there any way to solve this at all?
EDIT: Neither ReturnC nor ReturnB are derived from ReturnA. Updated with examples.

Error using the generic type BaseUser requires 1 argument

I have an interface
public interface IIdentity<T>
{
T GetUser();
}
I have a base class that implements the Interface as an abstract method
public abstract class BaseUser<T> : IIdentity<T>
{
public string UserId { get; set; }
public string AuthType { get; set; }
public List<Claim> Claims { get; set; }
public abstract T GetUser();
}
In the class that inherits the base class
public class JwtUser : BaseUser
{
public string Sub { get; set; }
}
I get an error using the generic type BaseUser requires 1 argument, what do i do here, basically I'd like my user to inherit shared properties from the base class which it does (i think) and to implement the generic method from the base class as I'm going to have different types of users (JWT/Windows etc) I need to abstract away the getUsers method, hope that makes sense ?
You have to ways to implement this, both require to set the generic in BaseUser.
You could expose that generic:
public class JwtUser<T> : BaseUser<T>
{
public string Sub { get; set; }
}
Or, just set the generic:
public class JwtUser : BaseUser<JwtUser>
{
public string Sub { get; set; }
}
it should be like , for Ref : Generic Classes (C# Programming Guide)
public class JwtUser<User> : BaseUser<User>
{
public string Sub { get; set; }
}
or
public class JwtUser<T> : BaseUser<T>
{
public string Sub { get; set; }
}
and when create instace
var jwtUser =new JwtUser<User> ();
or
class JwtUser: BaseUser<JwtUser> { }
In all way at the end you must need to specify value for T template as its generic.
For example if you take List<T> for using it you must need to intialize with proper type like if interger list then List<int> intlist = new List<int>();

C# Interface enforcing property that is another Interface?

Given this code:
public interface ITagModel { }
public interface ITemplate {
ITagModel Model { get; set; }
}
public class EmailTag : ITagModel { }
public class EmailTest : ITemplate {
public EmailTag Model { get; set; }
}
I am being told that the Type of EmailTag (inside EmailClass) cannot implement the Property Model because it is not the type ITagModel.
It is inheriting ITagModel....so why won't this work? What can I do to accomplish what I'm looking for?
C# doesn't support covariant return.
e.g.
public class Base { }
public class Derived : Base { }
public class Component
{
public virtual Base GetComponent()
{
return new Base();
}
}
public class DerviedComponent : Component
{
public override Dervied GetComponent()
{
return new Derived();
}
}
So you'll need to abstract the return type and constrain it to your interface. That way any implementation will need to supply an ITagModel.
public interface ITagModel { }
public interface ITemplate<TModel>
where TModel : ITagModel
{
TModel Model { get; set; }
}
public class EmailTag : ITagModel { }
public class EmailTest : ITemplate<EmailTag> {
public EmailTag Model { get; set; }
}
It sounds like your ITemplate interface should be generic:
public interface ITemplate<TModel> where TModel : ITagModel
{
TModel Model { get; set; }
}
Then:
public class EmailTest : ITemplate<EmailTag>
{
public EmailTag Model { get; set; }
}
Imagine if your current code worked. I could then write:
ITemplate template = new EmailTest();
template.Model = new SomeOtherModel();
... and you wouldn't want that. (Basically, you'd be violating type safety.)

Categories