Reputation: 2427
The problem I'm actually working on is related to mappers in ASP.NET MVC but that's way too complex to post on SO, so I've simplified the issue I'm having below. I'll post my code first as it's easier to explain what I'm trying to achieve after the code.
Supporting Code
public abstract class BaseFoo
{
public int CommonProperty { get; set; }
}
public class Foo1 : BaseFoo
{
public int SomeProperty { get; set; }
}
public class Foo2 : BaseFoo
{
public int AnotherProperty { get; set; }
}
public interface IMyInterface<T>
{
void SomeMethod(T t);
}
public abstract class BaseClass<T> : IMyInterface<T>
where T : BaseFoo
{
public virtual void SomeMethod(T t)
{
t.CommonProperty = 1;
}
}
public class ConcreteClass1 : BaseClass<Foo1>
{
public override void SomeMethod(Foo1 t)
{
t.SomeProperty = 57;
base.SomeMethod(t);
}
}
public class ConcreteClass2 : BaseClass<Foo2>
{
public override void SomeMethod(Foo2 t)
{
t.AnotherProperty = 123;
base.SomeMethod(t);
}
}
public static class ConcreteClassFactory
{
public enum ConcreteClassType
{
ConcreteClass1,
ConcreteClass2
}
public static dynamic CreateClass(ConcreteClassType type)
{
dynamic toReturn = null;
switch (type)
{
case ConcreteClassType.ConcreteClass1:
toReturn = new ConcreteClass1();
break;
case ConcreteClassType.ConcreteClass2:
toReturn = new ConcreteClass2();
break;
default:
break;
}
return toReturn;
}
}
What I want to do is dynamically create different ConcreteClass
s and call SomeMethod
on that created object, basically I want to pass around my ConcreteClass
s as BaseClass
, much like you can pass around Foo
s as BaseFoo
. I've gotten it to work with the following code:
class Program
{
static void Main(string[] args)
{
BaseFoo foo = new Foo1();
dynamic bar = ConcreteClassFactory.CreateClass(ConcreteClassFactory.ConcreteClassType.ConcreteClass1);
bar.SomeMethod(foo as dynamic);
}
}
However, this seems very kludgy to cast to a dynamic (also I don't fully understand why removing as dynamic
throws a RuntimeBinderException
, if someone can explain what's going on that would be appreciated). Is there a better way to achieve what I'm trying to do here?
Upvotes: 0
Views: 75
Reputation: 127563
With the constraints you have what I would do would be to cast and throw errors from inside the overridden SomeMethod.
public abstract class BaseClass : IMyInterface<BaseFoo>
{
public virtual void SomeMethod(BaseFoo t)
{
t.CommonProperty = 1;
}
}
public class ConcreteClass1 : BaseClass
{
public override void SomeMethod(BaseFoo t)
{
if(t == null)
throw new ArgumentNullException(nameof(t));
var foo1 = t as Foo1;
if(foo1 == null)
throw new NotSupportedException($"{nameof(ConcreteClass1)} does not support types other than {nameof(Foo1)}");
foo1.SomeProperty = 57;
base.SomeMethod(foo1);
}
}
public class ConcreteClass2 : BaseClass
{
public override void SomeMethod(BaseFoo t)
{
if (t == null)
throw new ArgumentNullException(nameof(t));
var foo2 = t as Foo2;
if (foo2 == null)
throw new NotSupportedException($"{nameof(ConcreteClass2)} does not support types other than {nameof(Foo2)}");
foo2.AnotherProperty = 123;
base.SomeMethod(foo2);
}
}
public static class ConcreteClassFactory
{
public enum ConcreteClassType
{
ConcreteClass1,
ConcreteClass2
}
public static BaseClass CreateClass(ConcreteClassType type)
{
BaseClass toReturn = null;
switch (type)
{
case ConcreteClassType.ConcreteClass1:
toReturn = new ConcreteClass1();
break;
case ConcreteClassType.ConcreteClass2:
toReturn = new ConcreteClass2();
break;
default:
break;
}
return toReturn;
}
}
Used like
class Program
{
static void Main(string[] args)
{
BaseFoo foo = new Foo1();
var bar = ConcreteClassFactory.CreateClass(ConcreteClassFactory.ConcreteClassType.ConcreteClass1);
bar.SomeMethod(foo);
}
}
Upvotes: 1