قم بإنشاء الاسم وتجميعه لفهرسة الترجمة/التعيين من أجل إعادة الاستخدام بشكل أسرع

StackOverflow https://stackoverflow.com//questions/11665503

  •  11-12-2019
  •  | 
  •  

سؤال

لنفترض أنني حصلت على بيانات من خدمة (لا أستطيع التحكم فيها) على النحو التالي:

public class Data
{
    // an array of column names
    public string[] ColumnNames { get; set; }

    // an array of rows that contain arrays of strings as column values
    public string[][] Rows { get; get; }
}

وفي الطبقة الوسطى أود تعيين/ترجمة هذا إلى ملف IEnumerable<Entity> حيث أسماء الأعمدة في Data ربما ممثلة كخصائص في بلدي Entity فصل.انا قلت يمكن لأنني قد لا أحتاج إلى جميع البيانات التي تعيدها الخدمة ولكن بعضها فقط.

تحويل

هذا تجريد للخوارزمية التي ستقوم بالترجمة:

  1. يخترع IDictionary<string, int> ل ColumnNames حتى أتمكن بسهولة من تعيين أسماء الأعمدة الفردية لصفيف المؤشرات في صفوف فردية.
  2. استخدام التفكير لفحص بلدي Entity أسماء الخصائص حتى أتمكن من مطابقتها مع أسماء الأعمدة
  3. التكرار من خلال Data.Rows وإنشاء بلدي Entity الكائنات وملء الخصائص وفقًا للتعيين الذي تم إجراؤه في رقم 1.من المحتمل استخدام الانعكاس و SetValue على خصائص لتعيينها.

تحسين

ستعمل الخوارزمية العليا بالطبع، لكنني أعتقد أنه نظرًا لأنها تستخدم الانعكاس، فيجب أن تقوم ببعض التخزين المؤقت وربما بعض عمليات التجميع السريعة، مما قد يؤدي إلى تسريع الأمور إلى حد كبير.

عند الانتهاء من الخطوتين 1 و2، يمكننا بالفعل إنشاء طريقة تأخذ مصفوفة من السلاسل وتنشئ مثيلاً للكيانات الخاصة بي باستخدام المؤشرات مباشرةً وتجميعها وتخزينها مؤقتًا لإعادة استخدامها في المستقبل.

عادةً ما أحصل على صفحة من النتائج، لذا فإن الطلبات اللاحقة ستعيد استخدام نفس الطريقة المجمعة.

حقيقة إضافية

هذا ليس ضروريًا للسؤال (والإجابات) ولكني قمت أيضًا بإنشاء سمتين تساعدان في تعيين العمود إلى الخاصية عندما لا تتطابق هذه السمات في الأسماء.لقد خلقت الأكثر وضوحا MapNameAttribute (يستغرق ذلك سلسلة ويمكّن أيضًا حساسية حالة الأحرف بشكل اختياري) و IgnoreMappingAttribute للعقارات على بلدي Entity لا ينبغي أن يتم تعيينها لأية بيانات.ولكن تتم قراءة هذه السمات في الخطوة 2 من الخوارزمية العليا بحيث يتم جمع أسماء الخصائص وإعادة تسميتها وفقًا لبيانات التعريف التعريفية هذه بحيث تتطابق مع أسماء الأعمدة.

سؤال

ما هي أفضل وأسهل طريقة لإنشاء وتجميع مثل هذه الطريقة؟تعبيرات لامدا؟ CSharpCodeProvider فصل؟

هل ربما يكون لديك مثال على التعليمات البرمجية التي تم إنشاؤها وتجميعها والتي تقوم بشيء مماثل؟أعتقد أن التعيينات هي سيناريو شائع إلى حد ما.

ملحوظة:في غضون ذلك، سأقوم بفحص PetaPoco (وربما أيضًا Massive) لأن كلا منهما يقوم بالتجميع والتخزين المؤقت بسرعة لأغراض رسم الخرائط تمامًا.

هل كانت مفيدة؟

المحلول

اقتراح: الحصول على FastMember من NuGet

ثم استخدم فقط:

var accessor = TypeAccessor.Create(typeof(Entity));

ثم فقط في حلقتك، عندما تجد memberName و newValue للتكرار الحالي:

accessor[obj, memberName] = newValue;

تم تصميم هذا للقيام بما تطلبه؛داخليا، فإنه يحتفظ بمجموعة من الأنواع إذا كان قد شاهدها من قبل.عندما يتم رؤية نوع جديد، فإنه يقوم بإنشاء فئة فرعية جديدة من TypeAccessor على الطاير (عبر TypeBuilder) ويخزنها مؤقتًا.كل فريدة من نوعها TypeAccessor على علم بخصائص هذا النوع، و أساسًا يتصرف فقط مثل:

switch(memberName) {
    case "Foo": obj.Foo = (int)newValue;
    case "Bar": obj.Bar = (string)newValue;
    // etc
}

نظرًا لأنه تم تخزينه مؤقتًا، فإنك تدفع فقط أي تكلفة (وليس في الواقع تكلفة كبير التكلفة) في المرة الأولى التي يرى فيها النوع الخاص بك؛وبقية الوقت، فهو مجاني.لأنه يستخدم ILGenerator مباشرة, ، كما أنه يتجنب أي تجريد غير ضروري، على سبيل المثال عبر Expression أو CodeDom، لذا فهو بأسرع ما يمكن.

(يجب أن أوضح ذلك أيضًا dynamic أنواع، أي.الأنواع التي تنفذ IDynamicMetaObjectProvider, ، يمكنه استخدام مثيل واحد لدعم كل كائن).


إضافي:

ما لك استطاع افعل هو:خذ الموجود FastMember الكود وتحريره للمعالجة MapNameAttribute و IgnoreMappingAttribute خلال WriteGetter و WriteSetter;ثم يحدث كل الفودو على الخاص بك بيانات الأسماء، وليس عضو أسماء.

وهذا يعني تغيير الخطوط:

il.Emit(OpCodes.Ldstr, prop.Name);

و

il.Emit(OpCodes.Ldstr, field.Name);

معا WriteGetter و WriteSetter, ، والقيام أ continue في بداية foreach الحلقات إذا كان ينبغي تجاهلها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top