5

私は辞書を持っています:

Dictionary<int, Type> AllDrillTypes = new Dictionary<int, Type>()
{
  {13,typeof(TCHEMISTRY)},
  {14,typeof(TDRILLSPAN)}
};

ここで、TCHEMISTRYとTDRILLSPANはクラスです。次に、このクラスの1つから次のような行を取得します。

Type T = AllDrillTypes[13];
var LC = Activator.CreateInstance( typeof(List<>).MakeGenericType( T ) );
MethodInfo M = T.GetMethod("FindAll", BindingFlags.Public | BindingFlags.Static, null, new Type[] { }, null);    
LC = M.Invoke(null, new object[] { });

このコードはすべて正しく機能します。その後、次のような行を取得する必要があります。

var LingLC = from obj in LC where obj.RunID == 1001 select obj;

しかし、この行はエラーを引き起こします:

「ソースタイプ'オブジェクト'のクエリパターンの実装が見つかりませんでした。'場所'が見つかりません。」

このコード行の何が問題になっていますか?

4

4 に答える 4

3

クラス定義を変更できない場合でも、リフレクションの使用を避けることができます。

// Getter dictionary rather than type dictionary.
Dictionary<int, Func<IEnumerable<object>>> DrillTypeGetters =
    new Dictionary<int, Func<IEnumerable<object>>>()   
    {  
        { 13, () => TCHEMISTRY.FindAll().Cast<object>() },
        { 14, () => TDRILLSPAN.FindAll().Cast<object>() }
    };
Dictionary<int, Func<object, int>> IDGetters =
    new Dictionary<int, Func<object, int>>()
    {
        { 13, o => ((TCHEMISTRY)o).RunID },
        { 14, o => ((TDRILLSPAN)o).RunID }
    };

IEnumerable<object> LC = DrillTypeGetters[13]();
IEnumerable<object> LingLC = 
    from obj in LC
    where IDGetters[13](obj) == 1001
    select obj;

13または、 /をオンにして、タイプごとにまったく異なるメソッド14を実行することもできます。

if (choice == 13)
    IEnumerable<TCHEMISTRY> LingLC =
        TCHEMISTRY.FindAll().Where(tc => tc.RunID == 1001);
else if (choice == 14)
    IEnumerable<TDRILLSPAN> LingLC =
        TDRILLSPAN.FindAll().Where(td => td.RunID == 1001);

基本的に、2つのクラスが共通の階層を共有していない場合、それらを処理するための共通のコードを作成することはできません。類似のプロパティがたくさんある場合は、最初の例のようにゲッターを使用して、処理しているクラスのタイプに関係なく、類似のプロパティを取得する方法を提供できます。それらが同様のプロパティを持っていない場合は、共有コードを作成しようとしないでください。

于 2012-10-17T08:41:35.753 に答える
1

たぶん、コードを次のようなものに書き直して、よりタイプセーフなソリューションを取得することができます(リフレクションを使用せずに)。

void Main()
{
    var driller1 = new DrillerWhichYouCannotChange1();
    var driller2 = new DrillerWhichYouCannotChange2();

    var allDrillTypes = new Dictionary<int, IList<IDriller>>()
    {
        { 13, new List<IDriller>() { new DrillerWhichYouCannotChange1Adapter(driller1) } },
        { 14, new List<IDriller>() { new DrillerWhichYouCannotChange2Adapter(driller2) } },
    };

    Console.WriteLine(allDrillTypes[13][0].SomeCommonProperty); // prints 123
    Console.WriteLine(allDrillTypes[14][0].SomeCommonProperty); // prints 456
}

interface IDriller
{
    int SomeCommonProperty { get; }
}

class DrillerWhichYouCannotChange1Adapter : IDriller
{
    private DrillerWhichYouCannotChange1 inner;

    public DrillerWhichYouCannotChange1Adapter(DrillerWhichYouCannotChange1 inner)
    {
        this.inner = inner;
    }

    public int SomeCommonProperty { get { return this.inner.PropertyX; } }
}

class DrillerWhichYouCannotChange2Adapter : IDriller
{
    private DrillerWhichYouCannotChange2 inner;

    public DrillerWhichYouCannotChange2Adapter(DrillerWhichYouCannotChange2 inner)
    {
        this.inner = inner;
    }

    public int SomeCommonProperty { get { return this.inner.PropertyY; } }
}

class DrillerWhichYouCannotChange1
{
    public int PropertyX { get { return 123; } }
}

class DrillerWhichYouCannotChange2
{
    public int PropertyY { get { return 456; } }
}

編集:ドリラークラスを変更できない場合は、adapter-patternを使用して、を実装するドリラーごとに1つのアダプターを作成できますIDiller

于 2012-10-17T08:37:34.527 に答える
0

LCをFindAllメソッドの戻り型にキャストする必要があります。次の行に何か:

var genericList = ((List<TChemistry>) LC);
var LingLC = from obj in genericList where obj.RunID == 1001 select obj;

これは、FindAllがTChemistryのコレクションを返すことを前提としています。

- 編集

タイプがTChemistryまたはTDrillspanのどちらであるかが実行時にわからない場合は、正しいタイプにキャストするために、switchステートメントのif/elseを記述する必要があります。むしろ、TChemistryとTDrillSpanに抽象クラスまたはインターフェイスを拡張してもらいたいのですが、Listにキャストするだけで、常にRunIdプロパティを使用できます。

public abstract class TAbstract
{
   public abstract int RunId {get; set;}
}

public class TChemistry : TAbstract
{
    public override int RunId {get; set;}
}

public class TDrillSpan : TAbstract
{
   public override int RunId {get; set;}
}

Type T = AllDrillTypes[13] as TAbstract;
var LC = Activator.CreateInstance( typeof(List<>).MakeGenericType( T ) );
MethodInfo M = T.GetMethod("FindAll", BindingFlags.Public | BindingFlags.Static, null, new Type[] { }, null);    
LC = M.Invoke(null, new object[] { });

var genericList = ((List<TAbstract>) LC);
var LingLC = from obj in genericList where obj.RunID == 1001 select obj;

クラスの宣言を変更できない場合は、次の場合にのみ醜いままになります。

var typeInfo = LC.GetType();
IEnumerable<T> genericList;
if (typeInfo == typeof(IEnumerable<TChemistry>)
{
    genericList = (List<TChemistry>) LC;
)
else if (typeInfo == typeof(IEnumerable<TDrillSpan>)
{
    genericList = (List<TDrillSpan>) LC;
}

var LingLC = from obj in genericList where obj.RunID == 1001 select obj;
于 2012-10-17T08:31:04.953 に答える
0

試す

IEnumerable returnedObjects = (IEnumerable)M.Invoke(null, new object[] { }) as IEnumerable;

次に、数え切れないほどの数を繰り返します

foreach (object report in returnedObjects)
{
    // Use reflection to read properties or add to a new List<object> if you
    // need an ICollection<object>
}

それ以外の :

LC = M.Invoke(null, new object[] { });
于 2012-10-17T08:50:45.540 に答える