2016-07-06 3 views
0

Проблема, над которой я нахожусь, связана с mappers в ASP.NET MVC, но это слишком сложно для публикации на SO, поэтому я упростил проблему, которая у меня ниже , Сначала я отправлю свой код, так как легче объяснить, что я пытаюсь достичь после кода.C# Наследование с помощью Generics и динамическое ключевое слово

Поддержка 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; 
    } 
} 

То, что я хочу сделать, это динамически создавать различные ConcreteClass с и называют SomeMethod на этом созданный объект, в основном я хочу передать вокруг моего ConcreteClass с, как BaseClass, так же, как вы можете перейдите около Foo с 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, если кто-то может объяснить, что это будет оценено по достоинству). Есть ли лучший способ достичь того, что я пытаюсь сделать здесь?

+0

Что вы хотите, чтобы произошло, когда кто-то проходит Foo2, чтобы ConcreteClass1? –

+0

Я понимаю, что мой оригинальный код не показал, почему я хотел иметь 'ConcreteClass1', чтобы использовать' Foo1' в качестве его параметра. @ScottChamberlain, если 'ConcreteClass1' должен был получить' Foo2', он должен выбросить ошибку. Очевидно, я мог бы избавиться от дженериков и иметь «SomeMethod (BaseFoo t)», но затем в каждом производном классе мне нужно попробовать и применить к 't' к типу, который он ожидает, а не ужасно, но не идеален для моих целей –

ответ

1

С ограничениями, которые у вас есть, что бы я делал, было бы бросить и выбросить ошибки из переопределенного 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); 
    } 
}