Typ anonimowy - utworzenie z istniejącego typu + dodanie pola

0

Witam,

Mam sobie coś takiego:

 
 ctx.RaportOsobyUprawnione.Select(x => 
new
	{
	 x.KO_SYMBOL,
	 x.OS_EMAIL,
	 x.OS_ID,
	 x.OS_IMIE,
	 x.OS_NAZWISKO,
	 x.OS_SYGNATURA_APS,
	 x.OS_UZYTKOWNIK,
	OPERATOR = ""
	}).ToList();

Jak widać, zapytanie zwraca nowy typ: wszystkie pola z RaportOsobyUprawnione + dodatkowo jedno pole OPERATOR, którego wartość zdefiniuję sobie później, póki co jest puste.
Jednak, muszę tu wypisywać wszystkie pola z RaportOsobyUprawnione, a chcę tego uniknąć. Czy nie da się jakoś pobrać wszystkich pól i wrzucić ich automatycznie do deklaratora typu, zamiast wypisywać po jednym? Jeśli będę mieć typ który ma 30 pól to nie chcę wszystkich ich wypisywać pojedynczo tylko po to żeby dodać nowe pole.

Jakieś sugestie?

0
 ctx.RaportOsobyUprawnione.Select(x => 
new { x,
        OPERATOR = ""
        }).ToList();

I wtedy masz:

ctx[n].x.elementy_i_funkcje_x
ctx[n].elementy_dodane_w_new (np. OPERATOR)
0

To sam wiedziałem. Problem w tym, że potrzebuję dokładnie takiej płaskiej listy, jaką otrzymam z zapytania w moim pytaniu, a nie część pól jako x.POLE a OPERATOR bezpośrednio - ma być płaska lista ze wszystkimi polami z RaportOsobyUprawnione i dodatkowo pole OPERATOR.

Czyli wszystko dodać w new, ale w new nie wymieniać wszystkich pól, tylko pobrać ich listę z RaportOsobyUprawnione.

0

A nie możesz olać typów anonimowych tylko napisać nową klasę rozszerzającą tą z polami o OPERATOR?

0

Ale co masz na myśli dokładnie? O ile wiem to nie można klasy rozszerzyć o pole, można tyko o metodę.

W sumie to mam tylko kilka takich zapytań, w których wcześniej było proste ToList a teraz po to aby dodać to jedno pole OPERATOR, muszę wypisywać wszystkie pola + to jedno. W pozostałych mam i tak bardziej skomplikowane SelectMany, gdzie wszystkie pola musiałem wypisać, więc dodanie jeszcze jednego tak bardzo mnie nie boli. Myślałem że można jakoś ładniej w tym przypadku, ale jeśli nie to trudno, przeżyję.

Mógłbym zapewne dodać jeszcze to pole OPERATOR w EntityFrameworku jako pole nie mapowane do bazy i tutaj nadać mu wartość - ale to na jedno wyjdzie, i tak bym musiał wszystkie pola wypisać tyle że by nie był anonimowy typ.

0
othello napisał(a):

Mógłbym zapewne dodać jeszcze to pole OPERATOR w EntityFrameworku jako pole nie mapowane do bazy i tutaj nadać mu wartość - ale to na jedno wyjdzie, i tak bym musiał wszystkie pola wypisać tyle że by nie był anonimowy typ.

Mi chodziło raczej o dziedziczenie z tej klasy EF, wtedy w nowej klasie dodasz tylko to jedno pole, więc wszystkich pól nie musisz wypisać.

Coś w tym rodzaju:

using System;
using System.Collections.Generic;
using Omu.ValueInjecter;

namespace ConsoleOthello
{
    // tej nie trzeba pisać, jest już gotowa
    class JakaśKlasaZEF
    {
        public string Pole1 { get; set; }
        public int Pole2 { get; set; }
    }

    class Wynik : JakaśKlasaZEF
    {
        public string Operator { get; set; }

        // do testów
        public override string ToString()
        {
            return string.Format("{0} {1} {2}", this.Pole1, this.Pole2, this.Operator);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var raport = new List<JakaśKlasaZEF> {
                new JakaśKlasaZEF { Pole1 = "A", Pole2 = 1, },
                new JakaśKlasaZEF { Pole1 = "B", Pole2 = 2, },
                new JakaśKlasaZEF { Pole1 = "C", Pole2 = 3, },
                new JakaśKlasaZEF { Pole1 = "D", Pole2 = 4, },
            };

            var wyniki = new List<Wynik>();
            raport.ForEach(x => {
                Wynik w = (Wynik)(new Wynik().InjectFrom(x));
                w.Operator = w.Pole1 + w.Pole2;
                wyniki.Add(w);
            });

            foreach (var w in wyniki)
            {
                Console.WriteLine(w);
            }

            Console.ReadLine();
        }
    }
}

Trzeba tylko w NuGecie dodać sobie ValueInjecter, żeby działało.

0

Rozwiązanie ciekawe, ale:

  • muszę korzystać z zewnętrznego frameworka tylko po to żeby wykonać 2 zapytania linq
  • to i tak więcej kodu, pomimo że rozwiązanie niby ładniejsze
0

E tam, to akurat malutka biblioteka, zawsze też możesz taki kod z niej skopiować/napisać samemu, to tylko refleksja.
Jak to więcej kodu? 4 linijki na definicję rozszerzonej klasy, za to zamiast Select z wypisanymi wszystkimi właściwościami masz ForEach, a w nim góra trzy linijki.
No, ale jak wolisz. :)

2

A musi to być typ anonimowy? Bo jeśli nie, to:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

namespace ConsoleOthello
{
    // tej nie trzeba pisać, jest już gotowa
    internal class JakaśKlasaZEF
    {
        public string Pole1 { get; set; }
        public int Pole2 { get; set; }
    }

    internal static class HardcoreExtensions
    {
        private static void AddProperty(TypeBuilder typeBuilder, string name, Type type, PropertyAttributes attriutes)
        {
            FieldBuilder fb = typeBuilder.DefineField("_" + name, type, FieldAttributes.Private);

            MethodBuilder gmb = typeBuilder.DefineMethod("get_" + name, MethodAttributes.Public | MethodAttributes.HideBySig, type, Type.EmptyTypes);
            ILGenerator gil = gmb.GetILGenerator();
            gil.Emit(OpCodes.Ldarg_0);
            gil.Emit(OpCodes.Ldfld, fb);
            gil.Emit(OpCodes.Ret);

            MethodBuilder smb = typeBuilder.DefineMethod("set_" + name, MethodAttributes.Public | MethodAttributes.HideBySig, null, new Type[] { type });
            ILGenerator sil = smb.GetILGenerator();
            sil.Emit(OpCodes.Ldarg_0);
            sil.Emit(OpCodes.Ldarg_1);
            sil.Emit(OpCodes.Stfld, fb);
            sil.Emit(OpCodes.Ret);

            PropertyBuilder pb = typeBuilder.DefineProperty(name, attriutes, type, new Type[] { type });
            pb.SetGetMethod(gmb);
            pb.SetSetMethod(smb);
        }

        public static IEnumerable<dynamic> SelectAndExtend<TSource>(this IEnumerable<TSource> source, object obj)
        {
            AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(new AssemblyName("DynamicAsembly"), AssemblyBuilderAccess.Run);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicAsembly.dll");
            TypeBuilder typeBuilder = moduleBuilder.DefineType("DynamicType", TypeAttributes.Public | TypeAttributes.Class);

            var oldProps = typeof(TSource).GetProperties();
            foreach (var op in oldProps)
            {
                AddProperty(typeBuilder, op.Name, op.PropertyType, op.Attributes);
            }

            var newProps = obj.GetType().GetProperties();
            foreach (var np in newProps)
            {
                AddProperty(typeBuilder, np.Name, np.PropertyType, np.Attributes);
            }

            Type dynamicType = typeBuilder.CreateType();

            var result = new List<dynamic>();
            foreach (var s in source)
            {
                dynamic dob = Activator.CreateInstance(dynamicType);

                var props = dynamicType.GetProperties();
                for (int i = 0; i < oldProps.Length; i++)
                {
                    var p = props.Single(q => q.Name == oldProps[i].Name);
                    p.SetValue(dob, oldProps[i].GetValue(s, null), null);
                }
                for (int i = 0; i < newProps.Length; i++)
                {
                    var p = props.Single(q => q.Name == newProps[i].Name);
                    p.SetValue(dob, newProps[i].GetValue(obj, null), null);
                }

                result.Add(dob);
            }

            return result;
        }
    }


    internal class Program
    {
        private static void Main(string[] args)
        {
            var raport = new List<JakaśKlasaZEF> {
				new JakaśKlasaZEF { Pole1 = "A", Pole2 = 1, },
				new JakaśKlasaZEF { Pole1 = "B", Pole2 = 2, },
				new JakaśKlasaZEF { Pole1 = "C", Pole2 = 3, },
				new JakaśKlasaZEF { Pole1 = "D", Pole2 = 4, },
			};

            var temp = raport.SelectAndExtend(new { OPERATOR = "", Cycki = 2 });

            foreach (var t in temp)
            {
                t.OPERATOR = t.Pole1 + t.Pole2;

                Console.WriteLine("{0} {1} {2} {3}", t.Pole1, t.Pole2, t.OPERATOR, t.Cycki);
            }

            Console.ReadLine();
        }
    }
} 

EDIT:
W sumie, to dzięki ExpandoObject można to napisać krócej i zgrabniej:

 public static IEnumerable<dynamic> SelectAndExtend<TSource>(this IEnumerable<TSource> source, object obj)
{
    var result = new List<dynamic>();
    foreach (var s in source)
    {
        IDictionary<string, object> newItem = new ExpandoObject();

        var sourceProps = s.GetType().GetProperties();
        foreach (var sp in sourceProps)
        {
            newItem[sp.Name] = sp.GetValue(s, null);
        }

        var anonProps = obj.GetType().GetProperties();
        foreach (var ap in anonProps)
        {
            newItem[ap.Name] = ap.GetValue(obj, null);
        }

        result.Add((dynamic)newItem);
    }

    return result;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1