كيف يمكنني إنشاء مثيل من نوع صفيف التعسفي في وقت التشغيل؟

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

سؤال

وأنا أحاول أن إلغاء تسلسل مجموعة من نوع غير معروف في وقت الترجمة. في وقت التشغيل لقد اكتشفت نوع، ولكن أنا لا أعرف كيف لإنشاء مثيل.

وشيء من هذا القبيل:

Object o = Activator.CreateInstance(type);

والذي لا يعمل لأنه لا يوجد منشئ parameterless، لا يبدو صفيف لديك أي المنشئ.

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

المحلول

استخدم Array.CreateInstance .

نصائح أخرى

ويمكنك استخدام واحدة من الزائدة CreateInstance صفيف ومنها مثلا: -.

object o = Array.CreateInstance(type, 10);

وبساطة وظيفة القديمة، ولكن بينما كان يجيب على سؤال جديد، على الرغم من نشر سبيل المثال ذات الصلة من خلق مجموعة ومتعددة الأبعاد.

وعلى افتراض نوع (elementType) كما int ومجموعة ثنائية الأبعاد على سبيل المثال.

var size = new[] { 2, 3 };                
var arr = Array.CreateInstance(typeof(int), size);

وعندما حان ثنائية الأبعاد، على سبيل المثال، يمكن مأهولة

var value = 1;
for (int i = 0; i < size[0]; i++)
    for (int j = 0; j < size[1]; j++)
        arr.SetValue(value++, new[] { i, j });
//arr = [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]

وبديل ذلك هو استخدام أشجار التعبير عن الأداء. على سبيل المثال؛ إذا كان لديك مجموعة <م> نوع ، type يمكن أن تفعله

var ctor = type.GetConstructors().First(); // or find suitable constructor
var argsExpr = ctor.GetParameters().Select(x => Expression.Constant(0)); 
var func = Expression.Lambda<Func<object>>(Expression.New(ctor, argsExpr)).Compile();

وهذا يعود مجرد مجموعة فارغة. ربما ليس من المفيد جدا. الدول MSDN GetConstructors لا يضمن أي أمر، لذلك قد تحتاج إلى المنطق للعثور على منشئ الصحيح مع المعلمات الصحيحة لمثيل مع الحجم الصحيح. على سبيل المثال؛ هل يمكن أن تفعل:

static Func<object> ArrayCreateInstance(Type type, params int[] bounds) // can be generic too
{
    var ctor = type
        .GetConstructors()
        .OrderBy(x => x.GetParameters().Length) // find constructor with least parameters
        .First();

    var argsExpr = bounds.Select(x => Expression.Constant(x)); // set size
    return Expression.Lambda<Func<object>>(Expression.New(ctor, argsExpr)).Compile();
}

والشيء نفسه يمكن تحقيقه أسهل بكثير مع Expression.NewArrayBounds بدلا من Expression.New، على مدى أكثر أنه يعمل إذا كان كل ما حصل هو مجموعة نوع العنصر، وليس نوع مصفوفة نفسها. عرض:

static Func<object> ArrayCreateInstance(Type type, params int[] bounds) // can be generic too
{
    var argsExpr = bounds.Select(x => Expression.Constant(x)); // set size
    var newExpr = Expression.NewArrayBounds(type.GetElementType(), argsExpr);
    return Expression.Lambda<Func<object>>(newExpr).Compile();
}

// this exercise is pointless if you dont save the compiled delegate, but for demo purpose:

x = string[] {...
y = ArrayCreateInstance(x.GetType(), 10)(); // you get 1-d array with size 10

x = string[,,] {...
y = ArrayCreateInstance(x.GetType(), 10, 2, 3)(); // you get 3-d array like string[10, 2, 3]

x = string[][] {...
y = ArrayCreateInstance(x.GetType(), 10)(); // you get jagged array like string[10][]

ومجرد تغيير type.GetElementType() إلى type ببساطة إذا كنت تمر هو نوع العنصر نفسه.

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