2011-04-20 5 views
0

매우 흥미로운 상황 이니 반사, 상속 및 제네릭을 둘러싼 웹에서 구체적인 내용을 찾을 수 없습니다.추상 클래스로 엔티티 프레임 워크 사용

로 시작하려면 내가 가진

기본 추상적이라고 분류 :

public abstract class ItemBase 
{ 
    // default properties 
} 

ItemBase는 될 항목라는 추상적 인 실체 내 슈퍼 클래스 :

public abstract class Item 
{ 
    // some extra properties 
} 

이 배경의 아이디어는 추가 속성이 설정된 Item에서 상속받을 엔터티를 만드는 것입니다.

public partial class City : Item {} 

이제 테스트 메소드에서 전달 된 엔티티에 대해 메소드를 호출하고 메소드에서 리턴 한 모든 데이터를 반환하려고합니다.

List<Item> cities = this.InvokeGenericMethod<Item>("State", "GetAllMajorCities", args); 
: 나는 모든 도시를 얻을 수있는 시험이있을 수 있습니다 내 스텁에서

public List<City> GetAllMajorCities() {} 

:

테스트를 위해 우리는 모든 주요 도시의 컬렉션을 반환 주에서 방법을 가지고, 가정

그런 다음 InvokeGenericMethod (문자열, 문자열, 객체 []에 args)을 보이는 뭔가 같은 :

public IEnumerable<T> InvokeGenericMethod<Item>(string className, string methodName, object[] args) 
{ 
    Type classType = className.GetType(); // to get the class to create an instance of 
    object classObj = Activator.CreateInstance(classType); 
    object ret = classType.InvokeMember(methodName, BindingFlags.InvokeMethod, null, classObj, args); 
} 

주어진 예제에서 이론적으로 "ret"값은 IEnumerable 유형이어야합니다. 그러나 ret 값을 다음과 같이 점검하면 반환 유형이 investivage에 추가 될 경우 List를 반환합니다.

if (ret is IEnumerable<T>) 

수표를 무시합니다.

내가 뭔가를 상속을 준수 나를 IEnumberable에 캐스팅 할 수 있도록 보인다

public List<City> GetAllMajorCities() {} 

public List<ItemBase> GetAllMajorCities() {} 

에 변경하는 경우.

나는 완전히 여기저기서 혼란 스럽다.

모든 아이디어, 권장 사항을 크게 높이 평가하겠습니다.

감사합니다,

에릭

+0

코드를 다시 확인해 주시겠습니까? 나는 여러 가지가 섞여 있다고 생각한다. InvokeGenericMethod가 작동하지 않을 것입니다. className.GetType()은 항상 유형 문자열을 반환합니다 (예 :). – Achim

+0

안녕하세요 아킴입니다. 위의 코드는 다소 혼란스러운 경우 실제 사과에 대한 예입니다. 클래스의 전체 이름에 리플렉션을 사용합니다. 드롭 다운 목록을 바인딩 할 때 문자열 형식의 클래스의 네임 스페이스를 사용합니다. 그런 다음이 문자열이 내 InvokeGenericMethod에 전달됩니다. – JadedEric

답변

3

Framework 3.5를 사용하고있을 가능성이 있습니까? Generic co-and contravariance는 .net 4.0에서 소개되었습니다. 따라서, 다음은 프레임 워크 3.5 수 없습니다 : 짝수 .NET 4.0에서 작동하지 않습니다 (당신이 달성하려고입니다) 다음과 같은 것을

class ItemBase { } 
class Item : ItemBase { } 
class City : Item { } 

class Program 
{ 
    static void Main(string[] args) 
    { 
     IEnumerable<City> cities = new List<City>(); 
     IEnumerable<Item> items = cities; // Compile error here. IEnumerable<Item> is not a supertype of IEnumerable<City>. 
    } 
} 

참고 :

List<Item> cities = new List<City>(); 

왜 그게 효과가 없니? List<Item>에 임의의 Item을 추가 할 수 있어야합니다. 하지만 분명히 cities.Add(new Person());은 "실제"(= 정적) 유형 citiesList<City>이므로 작동하지 않습니다. 따라서 List<Item>은 수퍼 유형 List<City>이 될 수 없습니다.

IEnumerable<City>IEnumerable<Item> 사이의 서브 타입 관계이 이유 (하지만 .NET 4.0은 위에서 언급 한 바와 같이,) 당신은 인를 IEnumerable 항목을 추가 할 수 없습니다.

+0

안녕하세요 Heinzi. 이해 해 주셔서 감사합니다. 이해가 잘못되었다는 것은 부울이 반영 될 때 하위 클래스가 자동으로 정의 될 수있는 ItemBase의 수퍼 클래스가 있기 때문입니다. 내 부분에 약간의 감독. – JadedEric

1

당신은 같은 것을 시도해 볼 수도 있습니다 : 모든

 Type type = ret.GetType(); 
     Type listType = typeof(IEnumerable<T>); 
     if (type == listType || type.IsSubclassOf(listType)) 
     { 
      // 
     } 
1

첫째, 이것은 잘못된 것입니다 :

Type classType = className.GetType(); 

이 구조는 유형을 얻을 것입니다 classNameString이지만 이름이 stor 인 유형은 아닙니다. 에 className에 ed.

더 나은, 더 형식 안전한 방법은 다음과 같습니다

public IEnumerable<TItem> InvokeGenericMethod<TItem, TContainer>(...) 
    where TItem : ItemBase 
    where TContainer : class, new() 
{ 
    TContainer container = new TContainer(); 
    ... 
} 

업데이트 : TContainer 유형이 InvokeGenericMethod가 호출되는 장소에서 정적으로 알 수없는 경우는의에보고를하여 staticType.GetType 문자열 이름에서 실제 이름을 확인하는 방법. 가장 간단한 경우 Type.GetType(String) 메서드는 어셈블리의 정규화 된 형식 이름 (예 : "MyNamespace.City, MyAssembly".

+0

안녕하세요 Ondrej, 귀하의 제안은 실제 클래스가 "순수한"형태로되어있는 상황에서 작동하지만, 엔티티 (클래스)의 이름을 문자열 값으로 나열하는 내 컨트롤의 드롭 다운 상자가 있습니다. 어셈블리에서 연결된 문자열의 기본 형식을 가져와야합니다. 논리를 변경하면 제안 된 솔루션이 유용 할 수도 있다고 생각하면서 더 자세히 조사 할 것입니다. – JadedEric

+0

@ JadedEric 정답을 수정하고 그에 따라 내 대답을 업데이트했습니다. 그러나 논리를보다 안전한 유형 솔루션으로 바꿀 수 있고 반성을 전혀 피할 수 있다면 미래에 일반적으로 이점을 얻을 수 있습니다. –