使用泛型和动态关键字进行 C# 继承
本文关键字:继承 关键字 动态 泛型 | 更新日期: 2023-09-27 17:55:14
我实际正在处理的问题与 MVC 中的映射器有关 ASP.NET 但这太复杂了,无法在 SO 上发布,所以我简化了我在下面遇到的问题。我将首先发布我的代码,因为更容易解释我在代码之后要实现的目标。
支持代码
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;
}
}
我想做的是动态创建不同的ConcreteClass
并在该创建的对象上调用SomeMethod
,基本上我想将我的ConcreteClass
传递为BaseClass
,就像您可以将Foo
s传递为BaseFoo
一样。我已经让它使用以下代码:
class Program
{
static void Main(string[] args)
{
BaseFoo foo = new Foo1();
dynamic bar = ConcreteClassFactory.CreateClass(ConcreteClassFactory.ConcreteClassType.ConcreteClass1);
bar.SomeMethod(foo as dynamic);
}
}
然而,这似乎非常笨拙地投射到动态(我也不完全明白为什么删除as dynamic
抛出一个RuntimeBinderException
,如果有人能解释发生了什么,那将不胜感激)。有没有更好的方法来实现我在这里想要做的事情?
有了约束,我要做的是从被覆盖的 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;
}
}
像这样使用
class Program
{
static void Main(string[] args)
{
BaseFoo foo = new Foo1();
var bar = ConcreteClassFactory.CreateClass(ConcreteClassFactory.ConcreteClassType.ConcreteClass1);
bar.SomeMethod(foo);
}
}