Hallo,
ich habe eine Frage ich möchte ein Property vom Typ Objekt setzen und habe einen String-Wert (Daten) und einen Typ (System.Type)
Hat jemand eine Idee, wie man am Besten den StringWert in den Typ konvertiert um ihn dann dem Property zuzuweisen.
Falls die generische Konvertierung (Parsing??) nicht klappt soll null zugewiesen werden.
Besten Dank für Eure Hilfe antoschka
Es soll im folgenden nicht pValue als String sondern als pType gebunden werden:
public object property;
public void SetValue(string pValue,System.Type pType)
{
// das klappt logischer Weise nicht.
this.property = (pType)pValue; // oder pValue as pType
}
Besten Dank für Eure Hilfe antoschka
Besten Dank. Sorry ich hatte einen kleinen Fehler in meiner Beschreibung.
Den Type bekomme ich auch als string in der Methoden signatur. Heißt also:
public void SetValue(string pValue,string pType)
{...}
Wie bekommt man das dann hin.
Vielen Dank für Euer Feedback antoschka
Korrekt. Im pValue steht ein String der einen Font, in einen Farbewert, Int32 etc konvertiert werden soll und dann dem Property zugeweisen werden muss.
Ich habe die Möglichkiet pValue statt als string auch einem beliebigen anderen aber einheitlichen Format zu übergeben (binary?)
Irgendeine Idee?
Besten Dank antoschka
sorry ich habe mich offensichtlich blöd ausgedrückt. Nochmal ich habe einen Wert mit Daten (bisher im string-format jedoch auch beliebig anders möglich - muss nur ein bestimmter Typ sein, da es aus einem Datenbank-Feld kommt) und ich habe zu jedem Datum einen Typ als string den ich mir aus einem anderen DB-Feld hole.
Ich habe also das Wertpaar "Arial", "System.Drawing.Font" oder "1234","System.Int64" und würde gern ein Property nicht mit den String Werten Arial oder 1234 füttern sondern mit den Font Arial bzw. der Long-Zahl 1234.
Wenn die Konvertierung des Strings in den Typ nicht klappt z.B. bei Wertpaaren
"1234", "System.Drawing.Font" oder "Arial","System.Int64" dann soll null zugewiesen werden.
Geht das irgendwie? Danke für Eure Hilfe antoschka
*heul* Ich habs gewusst. Ich kann das nicht. Kann mir jemand dabei helfen * schluchz*
besten Dank, werde ich tun! Könnte trotzdem jemand mir an diesem Bsp. abstarkt erklären, wie das Factory Pattern genutzt werden könnte.
lieben Dank Antoschka
Salute JAck30lena
Wie soll da das Factory-Pattern (Welches überhaupt) oder ein Microkernel helfen?
Ich habe sowas mal für alle ValueTypes + Guid und ein paar weitere implementiert, nur fürs Web - also alle Typen die durch einen String dargestellt werden.
Sowas in der Art:
public static T GetTypedValue<T>(string value) {
'// Implementation
}
Stichwörter: TypeConverter, Converter.ChangeType, IConvertible, Activator.CreateInstance, NullableType, ...
Gruss Peter
--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011
Die Methoden Signatur steht bei mir auch schon da, jedoch fehlt mir die Implementierung:
private T setTypedValue<T>(string pValue)
{
return (T)pValue;
}
Das war ja ich was JAck30lena angedeutet hat. nur leider funktioniert es nicht - Fehler: string kann nicht in T konvertiert werden 🙁
Könntest Du mir Deine Implementierung schicken?
Besten Dank antoschka
P.S.: Ist es vielleicht einfacher mit einem anderen Typ für die Daten z.B. binary-Array?
hallo Peter Bucher,
muss man beim typeconverter nciht für jeden typ eine separate unterscheidung machen. also sowas in der art:
switch(valueTypeString)
{
case "System.String":
property = value;
break;
case "System.Int32":
property = Int32.Parse(value);
break;
//usw...
default:
System.Diagnostics.Debug.Fail(
string.Format("Type '{0}' with value '{1}' not known", valueType, value));
property = null;
break;
}
?
Salute JAck30lena
Nö, wenn du mit Reflection arbeitest, nicht.
Bitte beantworte mir noch meine Fragen 🙂
Gruss Peter
--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011
Habe gerad ei BitConverter Klasse gefunden. Sagt mal wäre es nicht sinnvoller das DB-Feld meiner Daten als binary darzustellen und in c# byte[] zu verwenden. Dann könnte man mit der Klasse ziemlich viele Typen abdecken.
Besten Dank fürs Feedback antoschka
Hallo Peter Bucher,
factory:
http://www.codeproject.com/KB/cs/genericfactorycs.aspx
microkernel:
ich dachte immer das microkernel dazu da sind instanzen von registrierten typen anzulegen.
Hallo antoschka,
wenn du die datenbank beeinflussen kannst, warum verwendest du dann nciht serialisierung?
Hallo JAck30lena,
Also ich habe ein Datenmodlel und einen OR-Mapper drüber (NHibernate). Prinzipiell sollte sich an dem Konzept nicht ändern. Zentrale Tabelle ist eine AttributTabelle, die ein ValueFeld hat. Dieses ist zur Zeit vom Typ string, kann aber auch von einem beliebig anderen Typ sein.
Unter Beibehaltung des KOnzeptes, wie würdest Du es denn am Besten anstellen?
Besten Dank fürs Feedback antoschka
Moin,
"Type" kann übrigens auch einen "string" in den Typen zurückwandeln, nur dass ihr vor lauter Factory nicht vergesst.
🙂
Xynratron
Herr, schmeiss Hirn vom Himmel - Autsch!
Die Erfahrung zeigt immer wieder, dass viele Probleme sich in Luft auslösen, wenn man sich den nötigen Abstand bzw. Schlaf gönnt.
man kann auch jedes mal das Rad mit Hilfe von Factorys neu erfinden.
Besser, standardkonformer und einfacher (weil für diverse Typen schon im Framework definiert) gehts aber mit Convertern:
TypeConverter c = TypeDescriptor.GetConverter(t);
if (c.CanConvertFrom(typeof(string)))
return c.ConvertFrom(input);
else
//Pech gehabt, geht nicht
throw new NotSupportedException();
Ohne weiteres zutun werden jetzt schon Int16, Int32, Int32, Double, Decimal, sämtliche Enums, Boolean, DateTime, Point, Size, Rectangle u.v.m. unterstützt. Und wenn jetzt jemand seine ganz eigene Klasse, die du zur Compilezeit nicht kennst, erstellen will, dann brauch er nur einen TypeConverter schreiben und das sollte er eh tun, wenn es sinnvoll ist.
in den meisten Fällen geht auch einfach:
var newObject = Convert.ChangeType(oldValue, targetType);
Also ich hab das jetzt mal in eine Methode verpackt die ich per Reflection aufrufe (da T nicht zur DesignTime bekannt ist)
public object setAttributeValueToString<T>(string pValue)
{
if (typeof(T).Name == "String")
return nullString;
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
if (converter.CanConvertFrom(typeof(string)))
return converter.ConvertFrom(pValue == nullString ? default(T) : (object)pValue);
else
{
//throw new NotSupportedException();
return null;
}
}
Jetzt erhalte ich beim Aufruf der Methode eine TargetInvocationException:_
MethodInfo methodInfo = this.GetType().GetMethod("setAttributeValueToString", new System.Type[] { typeof(string) });
myValue = methodInfo.MakeGenericMethod(currentType).Invoke(this, new object[] { currentAttributValue.AttributeValueOfNode.ValueString });
wieso kann den der FontConverter nicht mit default(T) - wobei T eben "Font" ist - umgehen?
Besten Dank fürs Feedback
Hallo antoschka,
default (T) ist für Referenztypen null. Das wird also meistens unpassend sein.
Außerdem ist bei TargetInvocationException nur die InnerException interessant.
herbivore
Hallo zusammen
@JAck30lena
Eine Factory bring nur was, wenn du den Typ oder den Typnamen als String zu einem Objekt bringen möchtest.
Zusätzlich kannst du auch gut Polymorphie nutzen.
Für diesen Fall ist das IMO aber nichts.
Beim Microkernel denke ich auch das gleiche, zugegeben aber ohne viel Ahnung davon zu haben.
Schlussendlich geht es ja nur darum Stringwerte in den gewünschten Typ zu parsen und den Typ dann sicher zurückzugeben, bei Fehlschlag dann ggf. default(T) / also 0 / null oder du benutzt Nullable.
Hier mal meine Implementation - wie gesagt noch nicht optimal und primär fürs Web gedacht.
using System;
using System.ComponentModel;
using System.Reflection;
namespace pb.Web
{
public static partial class Tools
{
/// <summary>
/// Gibt ein Typisiertes Objekt vom angegebenen Typ zurück.
/// Unterstützt Value- und Referenztypen, sowie auch Nullable Typen.
/// + Guid
/// </summary>
/// <param name="value">Objekt das typisiert werden soll</param>
/// <returns>Typisiertes Objekt</returns>
public static T GetTypedValue<T>(object value) {
Type type = typeof(T); // gewünschter Typ
Type baseType = null; // gewünschter Untertyp (Wenn Nullable<>)
bool isValueType;
bool isNullable = false;
// Wenn ein Nullable<> Objekt eingespiesen wird, den unterliegenden Typ holen
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {
// get underlying type (struct type)
NullableConverter nc = new NullableConverter(type);
baseType = nc.UnderlyingType;
// Ist sowieso ein ValueType (Nullable geht nur auf ValueTypen)
isValueType = true;
isNullable = true;
} else {
// Checken ob Value- oder Referenztyp
isValueType = type.IsValueType;
}
// Richtigen Typ auswählen (Nullable / Normal)
type = baseType ?? type;
//// Wenn möglich, mit System.Convert.ChangeType() behandeln
//if(value is IConvertible) {
// IConvertible convertible = (IConvertible)value;
// return (T)Convert.ChangeType(value, type);
//}
IConvertible convertible = value as IConvertible;
if (value != null && convertible != null) {
try {
T result = (T)Convert.ChangeType(value, type);
return result;
} catch (Exception e) { /* Unten gehts weiter... */
}
}
// Methodeninfo holen, Signatur: void Parse(string source);
MethodInfo method = type.GetMethod(
"Parse",
new Type[] { typeof(string) },
new ParameterModifier[] {
new ParameterModifier(1)
});
// Default Value setzen (Für Valuetypen bspw. int=0, bool=false, ...)
T returnValue = default(T);
if (method != null && isValueType) {
try {
object parsedValue = method.Invoke(type,
new object[] { value.ToString() });
if (isValueType && isNullable) {
returnValue = (T)Activator.CreateInstance(typeof(T),
new object[] { parsedValue });
} else {
returnValue = (T)parsedValue;
}
} catch (Exception) {
// Wenn das Parsen fehlschlägt und wir einen Nullable Typ haben,
// eine leere Instanz (.HasValue = false) davon zurückgeben
if (isValueType && isNullable) {
returnValue = (T)Activator.CreateInstance(typeof(T));
}
}
} else {
// Referenztypen gecastet zurückgaben (Bspw. Strings)
// Guid wird ggf. geparst
if (type.IsAssignableFrom(Guid.NewGuid().GetType())) {
GuidConverter gc = new GuidConverter();
T g;
try {
g = (T)gc.ConvertFromString(value.ToString());
} catch (Exception) {
g = (T)(object)Guid.Empty;
}
if (g != null)
return g;
}
returnValue = (T)value;
}
return returnValue;
}
}
}
Anwendung bspw.:
object test = "122";
int typed = Tools.GetTypedValue<int>(test); // typed = 122
object test2 = null;
int typed2 = Tools.GetTypedValue<int>(test2); // typed2 = 0
object nothing = null;
string nothingTyped = Tools.GetTypedValue<string>(nothing); // nothingTyped = String.Empty;
object test3 = "keineGuid";
Guid? typed3 = Tools.GetTypedValue<Guid?>(test3);
if(typed3.HasValue) {
Guid guid = typed3.Value; // Gültige Guid
} else {
// Keine gültige Guid
}
Ich sollte TryParse statt Parse verwenden, das ganze noch ein wenig vereinfachen und die Try / Catches minimieren.
Gruss Peter
--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011
Und wenn DU einen nicht-String-Type in String umwandeln möchtest, was nimmst Du dann? den einfachen TypeConverter?
Besten Dank fürs feedback antoschka
Hallo antoschka,
Und wenn DU einen nicht-String-Type in String umwandeln möchtest, was nimmst Du dann?
.ToString ()
herbivore
Und darauf kann ich mich immer verlassen? Ich miene mich zu erinnern, dass es einige komische Standardimplementierungen für ToString gibt. Es kam jedenfalls imme rmal wieder im Forum vor.
antoschka