Vă mulțumim pentru susținere

Obțineți o instanță nouă de obiect dintr-un tip

Este posibil să nu cunoaștem întotdeauna tipul de obiect la timpul de compilare, dar poate fi necesar să creați o instanță a tipului. Cum obțineți o instanță nouă de tip dintr-un tip?

0
adăugat editat
Vorbim despre stratul de bază în ArcGIS 10?
adăugat autor Devdatta Tengshe
Cred că vorbește despre implementarea unui strat personalizat folosind clasa BaseCustomLayer.
adăugat autor Reed Copsey

13 răspunsuri

Ați încercat să obțineți din BaseCustomGlobeLayer în schimb?

Update: I just tried that and it doesn't work. I then derived from BaseCustomLayer then implemented IGraphicsContainer3D and was able to add it to the scene without getting an error.

2
adăugat
A creat următoarea întrebare aici gis.stackexchange.com/questions/18301/…
adăugat autor saint_groceon
Privind prin coclase care implementează ILayerEvents se pare că toate acestea fac ca o interfață de ieșire (cu excepția globului și a straturilor 3D). O întrebare bună ar fi: Cum să implementez mai multe interfețe de ieșire pentru clasele personalizate în C #?
adăugat autor saint_groceon
Cred că este o altă problemă legată de o interfață exterioară lipsă. În arcmap colaj de redare a imaginilor implementează ILayerEvents ca o interfață de ieșire. Suspectez documentație pentru graficlayer3d este incorectă și că ILayerEvents ar trebui să fie la ieșire, deoar
adăugat autor saint_groceon
@ReedCopsey Privind la OMD văd că GraphicsLayer3D implementează IActiveViewEvents ca interfață de ieșire. Cred că ItemDeleted trebuie să se declanșeze când graficele sunt eliminate.
adăugat autor saint_groceon
Nu eram sigur, până nu am încercat. Ai dreptate - nu lucrează cu ArcScene.
adăugat autor saint_groceon
IGraphicsContainer3D pare a fi cheia. Mulțumiri!
adăugat autor Thejesh GN
Nu este doar pentru ArcGlobe? Lucrează și în ArcScene?
adăugat autor Reed Copsey
@DBaker Ai reușit să lucrezi în cele din urmă? Am incercat acest lucru si in timp ce adauga fara eroare, comportamentul nu este "curat" (adica: grafica din IGraphicsContainer3D nu va elimina niciodata, etc) ...
adăugat autor Reed Copsey
@KirkKuykendall Tocmai am implementat întregul IActiveViewEvents (și ILayerEvents) și încă mai am același comportament ciudat ...
adăugat autor Reed Copsey
Nu este că am înlăturat grafice - chiar dacă am setat stratul Vizibilitatea la falsă nu determină ștergerea elementelor.
adăugat autor Reed Copsey

O implementare a acestei probleme este încercarea de a apela constructorul fără parametri al tipului:

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

Iată aceeași abordare, conținută într-o metodă generică:

public static T GetNewObject()
{
    try
    {
        return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return default(T);
    }
}
0
adăugat
Excepție determinată de programare? Acest lucru pare a fi o implementare foarte slabă atunci când puteți reflecta pur și simplu asupra tipului pentru a determina constructorii.
adăugat autor Firoso

Clasa Activator din spațiul de nume rădăcină System este destul de puternică.

Există o mulțime de supraîncărcări pentru trecerea parametrilor către constructor și altele asemenea. Consultați documentația la:

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

sau (calea nouă)

https://docs.microsoft.com/en- ne / DOTNET / api / system.activator.createinstance

Iată câteva exemple simple:

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

ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");
0
adăugat
Mă bucur că am găsit acest lucru în cele din urmă, dar că al doilea apel nu este exact drept, lipsesc o cotatie și params inversat ar trebui să fie: ObjectType instance = (ObjectType) Activator.CreateInstance ("MyAssembly", "MyNamespa & zwnj; ce.ObjectType");
adăugat autor kevinc
Trebuie să apelați 'Unwrap ()' pentru a obține tipul real de obiect pe care îl doriți: ConcreteType instance = (ConcreteType) Activator.CreateInstance (objectType) .Unwrap ();
adăugat autor Ε Г И І И О

Fără utilizarea reflecției:

private T Create() where T : class, new()
{
    return new T();
}
0
adăugat
Știți toate tipurile posibile la timpul de compilare, dar nu știți care va fi implementarea la runtime.
adăugat autor Robert P.
Dacă lucrați cu clase generice și interfețe în fabrici, tipurile care implementează interfața ar trebui să fie instanțiate pot varia.
adăugat autor Robert P.
un nou T (); ar eșua dacă T nu este un tip de referință cu constructor fără parametri. Această metodă folosește contraints pentru a asigura că T este tipul de referință și are un constructor.
adăugat autor Robert P.
Deci T poate varia în timpul rulării. Utile dacă lucrați cu tipuri diferite.
adăugat autor Robert P.
@RobertP. Puteți crea noi tipuri în timpul rulării. Nu există o regulă care să spună că știi toate tipurile la timpul de compilare. Și nu vreau să spun cu generice. Puteți crea tipuri complet noi și adăugați toate câmpurile, proprietățile și metodele etc. în timpul rulării. Există, de asemenea, cazul simplu în care doriți să creați o instanță de tip care se află într-un ansamblu care nu este cunoscut la momentul compilării. Acest lucru este destul de comun.
adăugat autor AnorZaken
Cum poate varia T în timpul execuției? Nu trebuie sa stii T la momentul designului pentru a apela Create <>?
adăugat autor Kyle Delaney
Cum este util acest lucru? Trebuie să cunoașteți tipul deja folosit pentru a apela această metodă și dacă știți tipul pe care îl puteți construi fără o metodă specială.
adăugat autor Kyle Delaney

Pot să trec peste această întrebare deoarece am vrut să pun în aplicare o metodă simplă CloneObject pentru o clasă arbitrară (cu un constructor implicit)

Cu metoda generică puteți cere ca tipul să implementeze funcția New ().

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

Cu presupunerea non-generică, tipul are un constructor implicit și o captură o excepție dacă nu.

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
0
adăugat

N-ar fi generic Tt = new T (); să funcționeze?

0
adăugat
De fapt, ar fi într-o clasă / metodă generică, dar nu pentru un anumit "tip".
adăugat autor Brady Moritz
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);

Clasa Activator are o variantă generică care face acest lucru un pic mai ușor:

ObjectType instance = Activator.CreateInstance();
0
adăugat
@Kevin Bineînțeles. O astfel de operație nu poate funcționa într-un limbaj static, deoarece nu are sens. Nu puteți invoca metode pe un obiect de tip necunoscut. Între timp, C # are constructul dinamic , care permite acest tip de construcție, dar pentru cele mai multe scopuri acest răspuns încă o acoperă.
adăugat autor Konrad Rudolph
@AnorZaken Comentariul meu nu spune nimic despre crearea tipurilor la timpul de executie. Bineînțeles că puteți face acest lucru, dar nu le puteți folosi în static în același context (puteți găzdui un program complet compilat static, desigur). Asta-i tot ce-mi spune comentariul.
adăugat autor Konrad Rudolph
Cu excepția faptului că nu funcționează pentru timpul de execuție Type t .
adăugat autor Kevin P. Rice
@KonradRudolph Îmi pare rău, a interpretat greșit "o astfel de operațiune" pentru a reprezenta instanțierea unui tip care este cunoscut doar la runtime; în loc de a însemna folosirea unui tip de runtime ca parametru de tip generic.
adăugat autor AnorZaken
@KonradRudolph Nu este chiar adevărat. În primul rând, c # vă permite să creați noi tipuri în timpul rulării. Pur și simplu nu le poți suna într-un mod sigur din punct de vedere static . Deci da, ești pe jumătate corectă. Dar, mai realist, aveți nevoie de acest lucru atunci când încărcați ansambluri la timpul de execuție, ceea ce înseamnă că tipul nu este cunoscut la momentul compilării. C # ar fi foarte limitat dacă nu ai putea face asta. Vreau să spun că tocmai v-ați dovedit: cum altfel metoda Activator ia o activitate de tip de tip? Când MS a scris clasa Activator, ei nu aveau
adăugat autor AnorZaken

Exprimarea compilată este cea mai bună cale! (pentru ca performanța să creeze în mod repetat instanță în timpul rulării).

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

X x = YCreator();

Statistici (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

Statistici (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

Statistici (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

Statistici (2017, LINQPad 5.22.02 / x64 / .NET 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

Cod complet:

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 YCreator = Expression.Lambda>(
   Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
).Compile();
static X CreateY_CompiledExpression()
{
    return YCreator();
}

private static readonly Func YCreator_Type = Expression.Lambda>(
   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 YCreator_Arg = Expression.Lambda>(
   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)CreateY_CreateInstance},
        new {Name = "Activator.CreateInstance(Type type)", Creator = (Func)CreateY_CreateInstance},
        new {Name = "ConstructorInfo.Invoke", Creator = (Func)CreateY_Invoke},
        new {Name = "Compiled expression", Creator = (Func)CreateY_CompiledExpression},
        new {Name = "Compiled expression (type)", Creator = (Func)CreateY_CompiledExpression_Type},
        new {Name = "new", Creator = (Func)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)CreateY_CreateInstance_Arg},
        new {Name = "ConstructorInfo.Invoke", Creator = (Func)CreateY_Invoke_Arg},
        new {Name = "Compiled expression", Creator = (Func)CreateY_CompiledExpression_Arg},
        new {Name = "new", Creator = (Func)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) {}
}
0
adăugat
Exemplu, poate?
adăugat autor ajeh
Este aceasta folositoare atunci când nu știți ce tip de X se află la runtime?
adăugat autor ajeh
De asemenea, există TypeDescriptor.CreateInstance (consultați stackoverflow.com/a/17797389/1242 ) care poate fi mai rapid dacă este utilizat cu TypeDescriptor .AddProvider
adăugat autor Lars Truijens
@ Serj-Tm Nu, nu va funcționa dacă tipul X este un Type de rulare.
adăugat autor NetMage
@ajeh Da. Schimbați tipul (T) la Type.GetType (..).
adăugat autor Serj-Tm
+1 pentru toate statisticile! Nu am nevoie de acest gen de performanță în acest moment, dar este încă foarte interesant. :)
adăugat autor AnorZaken

E destul de simplu. Să presupunem că numele dvs. de clasă este Mașină și spațiul de nume este Vehicles , apoi parcurgeți parametrul ca Vehicles.Car care returnează obiect de tip < . Astfel puteți crea dinamic orice instanță a oricărei clase.

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

Dacă numele dvs. complet calificat (adică , Vehicles.Car în acest caz) este într-un alt ansamblu, Type.GetType va fi nul. În astfel de cazuri, aveți o buclă prin toate ansamblurile și găsiți Type . Pentru asta poți folosi codul de mai jos

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;
 }

Și puteți obține instanța apelând metoda de mai sus.

object objClassInstance = GetInstance("Vehicles.Car");
0
adăugat
@danmiser Asta necesită codarea greșită a numelui ansamblului. În scopul de a implementa flexibilitatea am verificarea null și codul funcționează în mod dinamic :)
adăugat autor Sarath Avanavu
În cel de-al doilea caz (ansamblu extern), ai putea să treci în "Vehicles.Car, OtherAssembly" la prima ta metodă și va funcționa. Evident, alta asamblare este numele ansamblului in care locuieste.
adăugat autor danmiser

Dacă este vorba despre ceva care va fi numit mult într-o instanță de aplicație, este mult mai rapid să compilați și să stocați în memoria cache codul dinamic în loc să utilizați activatorul sau ConstructorInfo.Invoke () . Două opțiuni ușoare pentru compilarea dinamică sunt compilate Expresii Linq sau unele simple IL și DynamicMethod . În orice caz, diferența este mare atunci când începeți să ajungeți în bucle sau mai multe apeluri multiple.

0
adăugat
Linkul "IL opcodes and DynamicMethod" este mort.
adăugat autor Judge Bread
public AbstractType New
{
    get
    {
        return (AbstractType) Activator.CreateInstance(GetType());
    }
}
0
adăugat

Dacă doriți să utilizați constructorul implicit, atunci soluția folosind System.Activator prezentată mai devreme este probabil cea mai convenabilă. Cu toate acestea, în cazul în care tipul nu are un constructor implicit sau trebuie să utilizați un non-implicit, atunci o opțiune este să utilizați reflecția sau System.ComponentModel.TypeDescriptor . În cazul reflexiei, este suficient să cunoaștem doar numele de tip (cu spațiul său de nume).

Exemplu utilizând reflexia:

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
    );

Exemplu utilizând 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 }
    );
0
adăugat

Având în vedere această problemă, Activator va funcționa atunci când există un ctor fără parametru. Dacă aceasta este o constrângere, luați în considerare utilizarea

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
0
adăugat