Αποκτήστε ένα νέο στιγμιότυπο αντικειμένου από μία Τύπος

ψήφοι
554

Κανείς δεν μπορεί να γνωρίζει πάντα τον τύπο ενός αντικειμένου κατά τη μεταγλώττιση χρόνο, αλλά μπορεί να χρειαστεί να δημιουργήσετε μια παρουσία του Τύπου. Πώς μπορείτε να πάρετε ένα νέο αντικείμενο παράδειγμα από έναν Τύπος;

Δημοσιεύθηκε 03/08/2008 στις 17:29
πηγή χρήστη
Σε άλλες γλώσσες...                            


12 απαντήσεις

ψήφοι
709

Η Activatorτάξη στο εσωτερικό της ρίζας Systemονομάτων είναι αρκετά ισχυρό.

Υπάρχουν πολλοί υπερφορτώσεις για το πέρασμα παραμέτρων με τον κατασκευαστή και τέτοια. Ελέγξτε την τεκμηρίωση στη διεύθυνση:

http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx

ή (νέα διαδρομή)

https://docs.microsoft.com/en-us/dotnet/api/system.activator.createinstance

Εδώ είναι μερικά απλά παραδείγματα:

ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);

ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");
Απαντήθηκε 03/08/2008 στις 17:35
πηγή χρήστη

ψήφοι
113
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);

Η Activatorτάξη έχει μια γενική παραλλαγή που κάνει αυτό το λίγο πιο εύκολη:

ObjectType instance = Activator.CreateInstance<ObjectType>();
Απαντήθηκε 25/08/2008 στις 14:33
πηγή χρήστη

ψήφοι
78

Καταρτίζονται έκφραση είναι καλύτερο τρόπο! (Για την απόδοση σε επανειλημμένα δημιουργήσουν παράδειγμα σε χρόνο εκτέλεσης).

static readonly Func<X> YCreator = Expression.Lambda<Func<X>>(
   Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
 ).Compile();

X x = YCreator();

Στατιστικά στοιχεία (2012):

    Iterations: 5000000
    00:00:00.8481762, Activator.CreateInstance(string, string)
    00:00:00.8416930, Activator.CreateInstance(type)
    00:00:06.6236752, ConstructorInfo.Invoke
    00:00:00.1776255, Compiled expression
    00:00:00.0462197, new

Στατιστικές (2015, .net 4.5, x64):

    Iterations: 5000000
    00:00:00.2659981, Activator.CreateInstance(string, string)
    00:00:00.2603770, Activator.CreateInstance(type)
    00:00:00.7478936, ConstructorInfo.Invoke
    00:00:00.0700757, Compiled expression
    00:00:00.0286710, new

Στατιστικές (2015, .net 4.5, x86):

    Iterations: 5000000
    00:00:00.3541501, Activator.CreateInstance(string, string)
    00:00:00.3686861, Activator.CreateInstance(type)
    00:00:00.9492354, ConstructorInfo.Invoke
    00:00:00.0719072, Compiled expression
    00:00:00.0229387, new

Στατιστικές (2017, LINQPad 05.22.02 / x64 / ΝΕΤ 4.6):

    Iterations: 5000000
    No args
    00:00:00.3897563, Activator.CreateInstance(string assemblyName, string typeName)
    00:00:00.3500748, Activator.CreateInstance(Type type)
    00:00:01.0100714, ConstructorInfo.Invoke
    00:00:00.1375767, Compiled expression
    00:00:00.1337920, Compiled expression (type)
    00:00:00.0593664, new
    Single arg
    00:00:03.9300630, Activator.CreateInstance(Type type)
    00:00:01.3881770, ConstructorInfo.Invoke
    00:00:00.1425534, Compiled expression
    00:00:00.0717409, new

Πλήρης Κωδικός:

static X CreateY_New()
{
    return new Y();
}

static X CreateY_New_Arg(int z)
{
    return new Y(z);
}

static X CreateY_CreateInstance()
{
    return (X)Activator.CreateInstance(typeof(Y));
}

static X CreateY_CreateInstance_String()
{
    return (X)Activator.CreateInstance("Program", "Y").Unwrap();
}

static X CreateY_CreateInstance_Arg(int z)
{
    return (X)Activator.CreateInstance(typeof(Y), new object[] { z, });
}

private static readonly System.Reflection.ConstructorInfo YConstructor =
    typeof(Y).GetConstructor(Type.EmptyTypes);
private static readonly object[] Empty = new object[] { };
static X CreateY_Invoke()
{
    return (X)YConstructor.Invoke(Empty);
}

private static readonly System.Reflection.ConstructorInfo YConstructor_Arg =
    typeof(Y).GetConstructor(new[] { typeof(int), });
static X CreateY_Invoke_Arg(int z)
{
    return (X)YConstructor_Arg.Invoke(new object[] { z, });
}

private static readonly Func<X> YCreator = Expression.Lambda<Func<X>>(
   Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
).Compile();
static X CreateY_CompiledExpression()
{
    return YCreator();
}

private static readonly Func<X> YCreator_Type = Expression.Lambda<Func<X>>(
   Expression.New(typeof(Y))
).Compile();
static X CreateY_CompiledExpression_Type()
{
    return YCreator_Type();
}

private static readonly ParameterExpression YCreator_Arg_Param = Expression.Parameter(typeof(int), "z");
private static readonly Func<int, X> YCreator_Arg = Expression.Lambda<Func<int, X>>(
   Expression.New(typeof(Y).GetConstructor(new[] { typeof(int), }), new[] { YCreator_Arg_Param, }),
   YCreator_Arg_Param
).Compile();
static X CreateY_CompiledExpression_Arg(int z)
{
    return YCreator_Arg(z);
}

static void Main(string[] args)
{
    const int iterations = 5000000;

    Console.WriteLine("Iterations: {0}", iterations);

    Console.WriteLine("No args");
    foreach (var creatorInfo in new[]
    {
        new {Name = "Activator.CreateInstance(string assemblyName, string typeName)", Creator = (Func<X>)CreateY_CreateInstance},
        new {Name = "Activator.CreateInstance(Type type)", Creator = (Func<X>)CreateY_CreateInstance},
        new {Name = "ConstructorInfo.Invoke", Creator = (Func<X>)CreateY_Invoke},
        new {Name = "Compiled expression", Creator = (Func<X>)CreateY_CompiledExpression},
        new {Name = "Compiled expression (type)", Creator = (Func<X>)CreateY_CompiledExpression_Type},
        new {Name = "new", Creator = (Func<X>)CreateY_New},
    })
    {
        var creator = creatorInfo.Creator;

        var sum = 0;
        for (var i = 0; i < 1000; i++)
            sum += creator().Z;

        var stopwatch = new Stopwatch();
        stopwatch.Start();
        for (var i = 0; i < iterations; ++i)
        {
            var x = creator();
            sum += x.Z;
        }
        stopwatch.Stop();
        Console.WriteLine("{0}, {1}", stopwatch.Elapsed, creatorInfo.Name);
    }

    Console.WriteLine("Single arg");
    foreach (var creatorInfo in new[]
    {
        new {Name = "Activator.CreateInstance(Type type)", Creator = (Func<int, X>)CreateY_CreateInstance_Arg},
        new {Name = "ConstructorInfo.Invoke", Creator = (Func<int, X>)CreateY_Invoke_Arg},
        new {Name = "Compiled expression", Creator = (Func<int, X>)CreateY_CompiledExpression_Arg},
        new {Name = "new", Creator = (Func<int, X>)CreateY_New_Arg},
    })
    {
        var creator = creatorInfo.Creator;

        var sum = 0;
        for (var i = 0; i < 1000; i++)
            sum += creator(i).Z;

        var stopwatch = new Stopwatch();
        stopwatch.Start();
        for (var i = 0; i < iterations; ++i)
        {
            var x = creator(i);
            sum += x.Z;
        }
        stopwatch.Stop();
        Console.WriteLine("{0}, {1}", stopwatch.Elapsed, creatorInfo.Name);
    }
}

public class X
{
  public X() { }
  public X(int z) { this.Z = z; }
  public int Z;
}

public class Y : X
{
    public Y() {}
    public Y(int z) : base(z) {}
}
Απαντήθηκε 30/04/2015 στις 16:13
πηγή χρήστη

ψήφοι
35

Μία εφαρμογή αυτού του προβλήματος είναι να προσπαθήσει να καλέσει την παράμετρο-λιγότερο κατασκευαστή του τύπου:

public static object GetNewObject(Type t)
{
    try
    {
        return t.GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return null;
    }
}

Εδώ είναι η ίδια προσέγγιση, που περιέχεται σε μια γενική μέθοδο:

public static T GetNewObject<T>()
{
    try
    {
        return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return default(T);
    }
}
Απαντήθηκε 03/08/2008 στις 17:31
πηγή χρήστη

ψήφοι
11

Αν αυτό είναι κάτι που θα κληθεί πολύ σε ένα παράδειγμα εφαρμογής, είναι πολύ πιο γρήγορα για την κατάρτιση και την προσωρινή μνήμη δυναμικό κώδικα αντί να χρησιμοποιήσετε το ενεργοποιητή ή ConstructorInfo.Invoke(). Δύο εύκολες επιλογές για τη δυναμική συλλογή που καταρτίζονται Linq εκφράσεις ή μερικές απλές ILκώδικες λειτουργίας καιDynamicMethod . Είτε έτσι είτε αλλιώς, η διαφορά είναι τεράστια, όταν ξεκινάτε να πάρει σε στενούς βρόγχους ή πολλαπλές κλήσεις.

Απαντήθηκε 25/08/2008 στις 14:31
πηγή χρήστη

ψήφοι
9

Αρκετά απλό του. Ας υποθέσουμε ότι classname σας είναι Carκαι ο χώρος ονομάτων Vehicles, στη συνέχεια να περάσει την παράμετρο και Vehicles.Carη οποία επιστρέφει αντικείμενο του τύπου Car. Όπως μπορείτε να δημιουργήσετε οποιαδήποτε περίπτωση οποιασδήποτε κατηγορίας δυναμικά.

public object GetInstance(string strNamesapace)
{         
     Type t = Type.GetType(strNamesapace); 
     return  Activator.CreateInstance(t);         
}

Αν σας πλήρως αναγνωρισμένο όνομα (δηλαδή, Vehicles.Carστην προκειμένη περίπτωση) είναι σε μια άλλη διάταξη, η Type.GetTypeθα είναι μηδενική. Σε αυτές τις περιπτώσεις, θα πρέπει βρόχο μέσα από όλες τις συνελεύσεις και να βρει το Type. Για να μπορείτε να χρησιμοποιήσετε τον παρακάτω κώδικα

public object GetInstance(string strFullyQualifiedName)
{
     Type type = Type.GetType(strFullyQualifiedName);
     if (type != null)
         return Activator.CreateInstance(type);
     foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
     {
         type = asm.GetType(strFullyQualifiedName);
         if (type != null)
             return Activator.CreateInstance(type);
     }
     return null;
 }

Και μπορείτε να πάρετε το παράδειγμα καλώντας την παραπάνω μέθοδο.

object objClassInstance = GetInstance("Vehicles.Car");
Απαντήθηκε 03/11/2014 στις 06:11
πηγή χρήστη

ψήφοι
8

Χωρίς τη χρήση του προβληματισμού:

private T Create<T>() where T : class, new()
{
    return new T();
}
Απαντήθηκε 30/06/2015 στις 12:51
πηγή χρήστη

ψήφοι
7

Αν θέλετε να χρησιμοποιήσετε την προεπιλεγμένη κατασκευαστή τότε η λύση χρησιμοποιώντας System.Activatorπαρουσιάστηκε νωρίτερα είναι ίσως το πιο βολικό. Ωστόσο, αν ο τύπος δεν έχει μια προεπιλεγμένη κατασκευαστή ή θα πρέπει να χρησιμοποιήσετε ένα μη προεπιλεγμένο, τότε η επιλογή είναι να χρησιμοποιήσετε την αντανάκλαση ή System.ComponentModel.TypeDescriptor. Στην περίπτωση της ανάκλασης, αρκεί να γνωρίζουμε μόνο το όνομα του τύπου (με namespace του).

Παράδειγμα χρησιμοποιώντας αντανάκλαση:

ObjectType instance = 
    (ObjectType)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(
        typeName: objectType.FulName, // string including namespace of the type
        ignoreCase: false,
        bindingAttr: BindingFlags.Default,
        binder: null,  // use default binder
        args: new object[] { args, to, constructor },
        culture: null, // use CultureInfo from current thread
        activationAttributes: null
    );

Παράδειγμα χρησιμοποιώντας TypeDescriptor:

ObjectType instance = 
    (ObjectType)System.ComponentModel.TypeDescriptor.CreateInstance(
        provider: null, // use standard type description provider, which uses reflection
        objectType: objectType,
        argTypes: new Type[] { types, of, args },
        args: new object[] { args, to, constructor }
    );
Απαντήθηκε 22/07/2013 στις 22:03
πηγή χρήστη

ψήφοι
7

Δεν θα ήταν η γενική T t = new T();εργασία;

Απαντήθηκε 17/08/2010 στις 15:30
πηγή χρήστη

ψήφοι
5

Λόγω αυτού του προβλήματος το Activator θα λειτουργήσει όταν υπάρχει χωρίς παραμέτρους ctor. Εάν αυτό είναι ένα εμπόδιο να χρησιμοποιήσετε

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
Απαντήθηκε 30/06/2015 στις 16:35
πηγή χρήστη

ψήφοι
3

Μπορώ να σε αυτό το ερώτημα, γιατί έψαχνα να εφαρμόσει μια απλή μέθοδο CloneObject για την αυθαίρετη τάξη (με προεπιλεγμένο κατασκευαστή)

Με γενική μέθοδος που μπορεί να απαιτήσει ότι ο τύπος εφαρμόζει Νέα ().

Public Function CloneObject(Of T As New)(ByVal src As T) As T
    Dim result As T = Nothing
    Dim cloneable = TryCast(src, ICloneable)
    If cloneable IsNot Nothing Then
        result = cloneable.Clone()
    Else
        result = New T
        CopySimpleProperties(src, result, Nothing, "clone")
    End If
    Return result
End Function

Με μη-generic αναλάβει ο τύπος έχει ένα προεπιλεγμένο κατασκευαστή και να πιάσει μια εξαίρεση, αν δεν το κάνει.

Public Function CloneObject(ByVal src As Object) As Object
    Dim result As Object = Nothing
    Dim cloneable As ICloneable
    Try
        cloneable = TryCast(src, ICloneable)
        If cloneable IsNot Nothing Then
            result = cloneable.Clone()
        Else
            result = Activator.CreateInstance(src.GetType())
            CopySimpleProperties(src, result, Nothing, "clone")
        End If
    Catch ex As Exception
        Trace.WriteLine("!!! CloneObject(): " & ex.Message)
    End Try
    Return result
End Function
Απαντήθηκε 24/03/2015 στις 18:10
πηγή χρήστη

ψήφοι
3
public AbstractType New
{
    get
    {
        return (AbstractType) Activator.CreateInstance(GetType());
    }
}
Απαντήθηκε 10/09/2012 στις 00:08
πηγή χρήστη

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more