Laden...

Type einer generischen Instanz "weiter verwenden"

Erstellt von #CPferdchen vor 8 Jahren Letzter Beitrag vor 8 Jahren 1.454 Views
#
#CPferdchen Themenstarter:in
28 Beiträge seit 2011
vor 8 Jahren
Type einer generischen Instanz "weiter verwenden"

Hallo,

kann der Type einer Instanz eines generischen Objekts weiter verwendet werden?

Also etwas in der Art wie dieses (nicht ausführbar!) :


class Program
  {
    static void Main()
    {
      List<int> l1 = new List<int> ();

      Type type = l1.GetType ();
      
      List<type> l2 = new List<type> ();

    }
  }

Eine Möglichkeit die ich sehe wäre mir l1.GetType().ToString.Equals("ein Datentyp") zurück geben zu lassen und für jeden möglichen Typen eine eigene Initialisierung für l2 anzulegen. Aber das finde ich etwas sehr umständlich. Gibt es eine elegantere Lösung?

Leider finde ich keine passenden Beispiele oder ich suche nach den falschen Stichworten.

16.806 Beiträge seit 2008
vor 8 Jahren

Beschreib doch mal genau, was Du tun willst und welche Vorteile Du erwartest dann kann man die Anbieten, was man da machen kann.
Ich kann aus dem Konstrukt jedenfalls nicht erkenne, was Du vor hast und wozu das gut sein soll.

#
#CPferdchen Themenstarter:in
28 Beiträge seit 2011
vor 8 Jahren

Beschreib doch mal genau, was Du tun willst und welche Vorteile Du erwartest dann kann man die Anbieten, was man da machen kann.
Ich kann aus dem Konstrukt jedenfalls nicht erkenne, was Du vor hast und wozu das gut sein soll.


namespace DeviceComfortApp004
{
  class Channel<T> : ChannelBase
  {
    public T Value { get; set; }

    public override string ToString()
    {
      return "" + Value;
    }
  }
}

namespace DeviceComfortApp004
{
  class ChannelBase
  {
    public Address Address { get; set; }

    public string getChannelTyp()
    {
      return GetType().ToString();
    }

    public string getChannelAddress ()
    {
      return Address.ToString ();
    }
  }
}


namespace DeviceComfortApp004
{
  internal class Address
  {
    //Fields

    //Constructors
    public Address (int deviceTyp, int deviceNumber)
    {
      DeviceTyp = deviceTyp;
      DeviceNumber = deviceNumber;
    }

    //Methods
    public override string ToString()
    {
      return DeviceTyp + "." + DeviceNumber;
    }

    //Properties
    public int DeviceTyp { get; set; }
    public int DeviceNumber { get; set; }
  }
}

Diese Channels sollen verschiedene angeschlossene Geräte darstellen. Z.B. SPS, Usb-Geräte(serials Port mit Treiberbibliotheken) usw. Der User soll nun über die GUI eine neue Klasse erstellen können die die verschiedenen Channels beinhalten (mit CodeDome oder eher Roslyn). Die Klasse soll dann zum Beispiel so aussehen:


namespace DeviceComfortApp004
{
  class ApplicationChannels
  {
    //Fields
    public Channel<double> Voltage = new Channel<double>();
    public Channel<int> Length = new Channel<int>();
 
    //Constructor
    public ApplicationChannels()
    {
      Voltage.Address = new Address(0, 0);
      Length.Address  = new Address(0, 1);
    }

    //Methods

    //Properties
  }
}

Diese Channels will ich dann wiederum an Threads übergeben welche eine Queue mit zurückgebenen Werten der Geräte befüllt. Problem dabei ist ja, dass wenn ich einen generischen Typen einer Klasse übergeben will diese auch generisch sein muss. Also verwende ich meinen Basistypen von Channel ChannelBase als Übergabeparameter. Kann ich ja wieder zurück Konvertieren um an Value zu kommen.

Aber irgendwann muss ich ja auch wieder auf meine instanzieren Wert Value in der ChannelBase Instanz zugreifen und muss den tatsächlichen Typen wissen und eine Variable von genau diesem Typen angelegen können. Am besten ohne, dass ChannelThread selbst generisch sein muss... (siehe TRY/CATCH)


using System;
using System.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace DeviceComfortApp004
{
  class ChannelThread
  {
    //Gibt Wert von Channel zurück
    //generische Behandlung?

    private bool _shouldStop = false;
    public string value;
    private ChannelBase ChannelBase;
    private Stream Stream;
    private int Clock;
    

    public ChannelThread (ChannelBase channelBase, int clock)
    {
      ChannelBase = channelBase;
      Clock = clock;
    }

    public void TcpServerConnect(TcpClient tcpClient)
    {
      try
      {
        Stream = tcpClient.GetStream();
        Console.WriteLine("TCP Server connected \n");
        _shouldStop = false;

      }
      catch (Exception exception)
      {
        Console.WriteLine("TCP Server communication error\n" + exception.GetType());
      }
    }

    public void Run()
    {
      Stopwatch watch = new Stopwatch ();
      watch.Start ();

      while (!_shouldStop)
      {
        watch.Reset ();

        try
        {
          //HIER SOLL DER AKTUELLE WERT AUS DEM DEVICE 
          //THREAD GELESEN UND DANN GESENDET WERDEN!
          value = (Channel<HIER DOOF>)ChannelBase.Value.ToString ();

          Byte[] sendBytes = Encoding.ASCII.GetBytes(DateTime.Now.ToString() + " |> "+ value + "\r\n");
          Stream.Write (sendBytes, 0, sendBytes.Length);
        }
        catch (Exception exception)
        {
          Console.WriteLine ("TCP communication error\n" + exception.GetType ());
        }

        Thread.Sleep(Clock - (int)watch.ElapsedMilliseconds);
      }
    }

    public void ShouldStop()
    {
      _shouldStop = true;
    }
  }
}

#
#CPferdchen Themenstarter:in
28 Beiträge seit 2011
vor 8 Jahren

Ich hatte diesen Artikel im MSDN gefunden:
https://msdn.microsoft.com/de-de/library/b8ytshk6%28v=vs.110%29.aspx

Aber dort wird im zweiten Beispiel Punkt zwei auch vorrausgesetzt, dass der spätere Typ (string und Example) zur Laufzeit bekannt ist.

5.657 Beiträge seit 2006
vor 8 Jahren

Hi #CPferdchen,

es geht also um diese Code-Stelle:

         //HIER SOLL DER AKTUELLE WERT AUS DEM DEVICE   
          //THREAD GELESEN UND DANN GESENDET WERDEN!  
          value = (Channel<HIER DOOF>)ChannelBase.Value.ToString ();  
  

Warum wandelst du den Wert erst in eine Zeichenkette um, nur um ihn dann wieder auf deinen eigentlichen Typ zu casten? Es würde doch reichen, zu schreiben:


var value = ChannelBase.Value;

Wenn du einen (abstrakten) Basistyp definierst, kannst du auch folgendes schreiben:


public class ChannelBase<T> where T : SomeBaseClass
{ 
  public T Value { get; set; }
  // ...
}

SomeBaseClass value = ChannelBase.Value;

Wenn ich mir deine Anforderungen allerdings so anschaue:

Der User soll nun über die GUI eine neue Klasse erstellen können die die verschiedenen Channels beinhalten (mit CodeDome oder eher Roslyn).

dann würde ich aber empfehlen, dir zuerst einmal ein geeignetes Datenmodell zu entwerfen, das auch allen deinen Anforderungen entspricht. Das geht sicher auch ohne Reflection/CodeDom/Roslyn, sondern mit herkömmlicher objektorientierter Programmierung.

Christian

Weeks of programming can save you hours of planning

M
334 Beiträge seit 2007
vor 8 Jahren

Aber irgendwann muss ich ja auch wieder auf meine instanzieren Wert Value in der ChannelBase Instanz zugreifen und muss den tatsächlichen Typen wissen und eine Variable von genau diesem Typen angelegen können.

Für den Code, den du da gezeigt hast, ist das nicht notwendig.
Du rufst im Endeffekt ja nur ToString() auf und was da raus kommt bestimmt die jeweilige Implementierung von ChannelBase.

edit: zu spät