C#: How to use generic method with "out" variable - c#

I want to create a simple generic function
void Assign<T>(out T result)
{
Type type = typeof(T);
if (type.Name == "String")
{
// result = "hello";
}
else if (type.Name == "Int32")
{
// result = 100;
}
else result = default(T);
}
Usage:
int value;
string text;
Assign(value); // <<< should set value to 100
Assign(text); // <<< should set text to "hello"
My question is how do you program the code to set these values ie. the missing codes in comment section.
Thanks for any help.

It looks like in this case maybe you're doing it to try to avoid boxing? Difficult to say without more information, but for this specific example, it'd be much easier and probably less bug-prone to just use method overloading:
void Assign(out string value)
{
//...
}
void Assign(out int value)
{
//...
}
For the purposes of learning specifically what is wrong here, you do need to cast a value to an object before casting it to the generic type:
(T)(object)"hello world!";
Which IMO is pretty nasty and should be a last resort - certainly doesn't make your code any cleaner.
Any time you do type-checking of generic parameters, it's a good indication generics are not the right solution to your problem. Doing generic parameter type checks makes your code more complex, not simpler. It makes one method responsible for different behaviors based on type, instead of a series of single methods that are easy to change without accidentally affecting the others. See Single Responsibility Principle.

First of all that's a very bad pattern. You shouldn't use this kind of pattern. Maybe if you describe what you really want to achieve there will be better answers.
Code below works, but as I said writing code this way is a bad idea.
void Assign<T>(out T result)
{
Type type = typeof(T);
if (type.Name == "String")
{ result = (T) ((object)"hello"); }
else if (type.Name == "Int32")
{ result = (T) ((object)100); }
else result = default(T);
}
And usage:
int value;
string text;
Assign(out value);
Assign(out text);

public T GetObject<T>(string val)
{
T _object = default(T);
_object = (T)Convert.ChangeType(val, typeof(T));
return _object;
}

Here is one way:
static void Assign<T>(out T result) {
Type type = typeof(T);
if (type.Name == "String") {
result = (T)Convert.ChangeType("hello", typeof(T));
}
else if (type.Name == "Int32") {
result = (T)Convert.ChangeType(100, typeof(T));
}
else {
result = default(T);
}
}
But this code smells really bad and goes against the point of generics (instead use overloaded methods). I hope this doesn't end up in production code somewhere and is merely for edification.

Related

How to access base-class member using a generic-type constrained to interface? [duplicate]

This is likely a a novice question, but google surprisingly did not provide an answer.
I have this rather artificial method
T HowToCast<T>(T t)
{
if (typeof(T) == typeof(string))
{
T newT1 = "some text";
T newT2 = (string)t;
}
return t;
}
Coming from a C++ background I have expected this to work. However, it fails to compile with "Cannot implicitly convert type 'T' to string" and "Cannot convert type 'T' to string" for both of the above assignments.
I am either doing something conceptually wrong or just have the wrong syntax. Please help me sort this one out.
Thank you!
Even though it's inside of an if block, the compiler doesn't know that T is string.
Therefore, it doesn't let you cast. (For the same reason that you cannot cast DateTime to string)
You need to cast to object, (which any T can cast to), and from there to string (since object can be cast to string).
For example:
T newT1 = (T)(object)"some text";
string newT2 = (string)(object)t;
Both lines have the same problem
T newT1 = "some text";
T newT2 = (string)t;
The compiler doesn't know that T is a string and so has no way of knowing how to assign that.
But since you checked you can just force it with
T newT1 = "some text" as T;
T newT2 = t;
you don't need to cast the t since it's already a string, also need to add the constraint
where T : class
I know similar code that the OP posted in this question from generic parsers. From a performance perspective, you should use Unsafe.As<TFrom, TResult>(ref TFrom source), which can be found in the System.Runtime.CompilerServices.Unsafe NuGet package. It avoids boxing for value types in these scenarios. I also think that Unsafe.As results in less machine code produced by the JIT than casting twice (using (TResult) (object) actualString), but I haven't checked that out.
public TResult ParseSomething<TResult>(ParseContext context)
{
if (typeof(TResult) == typeof(string))
{
var token = context.ParseNextToken();
string parsedString = token.ParseToDotnetString();
return Unsafe.As<string, TResult>(ref parsedString);
}
else if (typeof(TResult) == typeof(int))
{
var token = context.ParseNextToken();
int parsedInt32 = token.ParseToDotnetInt32();
// This will not box which might be critical to performance
return Unsafe.As<int, TResult>(ref parsedInt32);
}
// other cases omitted for brevity's sake
}
Unsafe.As will be replaced by the JIT with efficient machine code instructions, as you can see in the official CoreFX repo:
If you're checking for explicit types, why are you declaring those variables as T's?
T HowToCast<T>(T t)
{
if (typeof(T) == typeof(string))
{
var newT1 = "some text";
var newT2 = t; //this builds but I'm not sure what it does under the hood.
var newT3 = t.ToString(); //for sure the string you want.
}
return t;
}
You will also get this error if you have a generic declaration for both your class and your method. For example the code shown below gives this compile error.
public class Foo <T> {
T var;
public <T> void doSomething(Class <T> cls) throws InstantiationException, IllegalAccessException {
this.var = cls.newInstance();
}
}
This code does compile (note T removed from method declaration):
public class Foo <T> {
T var;
public void doSomething(Class <T> cls) throws InstantiationException, IllegalAccessException {
this.var = cls.newInstance();
}
}
Change this line:
if (typeof(T) == typeof(string))
For this line:
if (t.GetType() == typeof(string))

C# get propery value from string path

Given any object, I want to be able to retrieve the value of a property and any "depth".
var name = myObject.GetValue<String>("Name")
or
var father_name = myObject.GetValue<String>("Father.Name")
This is easy and I'm able do achieve it with the following code:
public static T GetValue<T>(this Object obj, String fqname)
{
try
{
Object value = obj;
foreach (var prop in fqname.Split('.').Select(s => value.GetType().GetProperty(s)))
{
value = prop.GetValue(value, null);
}
if (value is T)
{
return (T)value;
}
else
{
// if the type requested is not the same as the stored, attempt a blind conversion
var converter = TypeDescriptor.GetConverter(typeof(T));
return (T)converter.ConvertFromInvariantString(value.ToString());
}
}
catch (NotSupportedException)
{
throw new InvalidCastException($"Cannot convert value to reuested type");
}
}
Now the problem is that this doesn't work for arrays, like:
var main_street = myObject.GetValue<String>("Addresses[0].StreetName")
Not even for the cases of arrays of arrays and so on...
I can start adding these conditions and special cases to my code but before that I figured, as C# already does this, maybe we could leverage some code parsing strategy, Roslyn, ... don't know, something that doesn't feel like reinventing the wheel and supports as many cases as possible.
Any ideas?

Get enum description of string value enum from string [duplicate]

This is likely a a novice question, but google surprisingly did not provide an answer.
I have this rather artificial method
T HowToCast<T>(T t)
{
if (typeof(T) == typeof(string))
{
T newT1 = "some text";
T newT2 = (string)t;
}
return t;
}
Coming from a C++ background I have expected this to work. However, it fails to compile with "Cannot implicitly convert type 'T' to string" and "Cannot convert type 'T' to string" for both of the above assignments.
I am either doing something conceptually wrong or just have the wrong syntax. Please help me sort this one out.
Thank you!
Even though it's inside of an if block, the compiler doesn't know that T is string.
Therefore, it doesn't let you cast. (For the same reason that you cannot cast DateTime to string)
You need to cast to object, (which any T can cast to), and from there to string (since object can be cast to string).
For example:
T newT1 = (T)(object)"some text";
string newT2 = (string)(object)t;
Both lines have the same problem
T newT1 = "some text";
T newT2 = (string)t;
The compiler doesn't know that T is a string and so has no way of knowing how to assign that.
But since you checked you can just force it with
T newT1 = "some text" as T;
T newT2 = t;
you don't need to cast the t since it's already a string, also need to add the constraint
where T : class
I know similar code that the OP posted in this question from generic parsers. From a performance perspective, you should use Unsafe.As<TFrom, TResult>(ref TFrom source), which can be found in the System.Runtime.CompilerServices.Unsafe NuGet package. It avoids boxing for value types in these scenarios. I also think that Unsafe.As results in less machine code produced by the JIT than casting twice (using (TResult) (object) actualString), but I haven't checked that out.
public TResult ParseSomething<TResult>(ParseContext context)
{
if (typeof(TResult) == typeof(string))
{
var token = context.ParseNextToken();
string parsedString = token.ParseToDotnetString();
return Unsafe.As<string, TResult>(ref parsedString);
}
else if (typeof(TResult) == typeof(int))
{
var token = context.ParseNextToken();
int parsedInt32 = token.ParseToDotnetInt32();
// This will not box which might be critical to performance
return Unsafe.As<int, TResult>(ref parsedInt32);
}
// other cases omitted for brevity's sake
}
Unsafe.As will be replaced by the JIT with efficient machine code instructions, as you can see in the official CoreFX repo:
If you're checking for explicit types, why are you declaring those variables as T's?
T HowToCast<T>(T t)
{
if (typeof(T) == typeof(string))
{
var newT1 = "some text";
var newT2 = t; //this builds but I'm not sure what it does under the hood.
var newT3 = t.ToString(); //for sure the string you want.
}
return t;
}
You will also get this error if you have a generic declaration for both your class and your method. For example the code shown below gives this compile error.
public class Foo <T> {
T var;
public <T> void doSomething(Class <T> cls) throws InstantiationException, IllegalAccessException {
this.var = cls.newInstance();
}
}
This code does compile (note T removed from method declaration):
public class Foo <T> {
T var;
public void doSomething(Class <T> cls) throws InstantiationException, IllegalAccessException {
this.var = cls.newInstance();
}
}
Change this line:
if (typeof(T) == typeof(string))
For this line:
if (t.GetType() == typeof(string))

Variable Return Type of a Method in C#

I want to give a parameter to a method and i want my method to return data by looking the parameter. Data can be in type of boolean, string, int or etc. How can i return a variable type from a method? I don't want to return an object type and then cast it to another type. For example:
BlaBla VariableReturnExampleMethod(int a)
{
if (a == 1)
return "Demo";
else if (a == 2)
return 2;
else if (a == 3)
return True;
else
return null;
}
The reason why i want that is i have a method that reads a selected column of a row from the database. Types of columns are not same but i have to return every column's information.
How can i return a variable type from a method? I don't want to return an object type and then cast it to another type.
Well that's basically what you do have to do. Alternatively, if you're using C# 4 you could make the return type dynamic, which will allow the conversion to be implicit:
dynamic VariableReturnExampleMethod(int a)
{
// Body as per question
}
...
// Fine...
int x = VariableReturnExampleMethod(2);
// This will throw an exception at execution time
int y = VariableReturnExampleMethod(1);
Fundamentally, you specify types to let the compiler know what to expect. How can that work if the type is only known at execution time? The reason the dynamic version works is that it basically tells the compiler to defer its normal work until execution time - so you lose the normal safety which would let the second example fail at compile time.
Use dynamic Keyword in place of BlahBlah if you are targeting .Net 4.0 but if lesser one then object is your safest bet because it is the base class for every other class you can think of.
It sounds like this might be a good case for generics. If you know what data type you're expecting when you call it, you can call that particular generic version of the function.
Consider using something like Dapper-dot-net (written by Marc Gravell and Sam Saffron at our very own Stack Overflow) to pull things out of the DB. It handles the database to object mapping for you.
Furthermore, if you don't want to use a tool, and you're pulling from a Database, and you know the data types of the various columns at compile time (like it sounds you do), you should probably be working row-by-row rather than column-by-column.
//Pseudo-code:
List<DatabaseObject> objects = new List<DatabaseObject>();
foreach(var row in DatabaseRows)
{
var toAdd = new DatabaseObject();
toAdd.StringTypeVariable = "Demo";
toAdd.IntTypeVariable = 2;
toAdd.BoolTypeVariable = true;
object.Add(toAdd);
}
Note: you could use object initializer syntax, and linq here but this is the most basic way I could think of demoing this without using a ton of extra stuff.
Also note, that here I'm assuming that you don't actually want to return "Demo", 2, and true, but values that use the row. That just means you'd change the hard coded values to: row.GetStringType(stringColumnIdx) or something similar.
Use return type as object, then you are able to get any return type. you have to handle the return type ether through reflection or other method.
check this:
void Main()
{
object aa = VariableReturnExampleMethod(3);
Console.WriteLine(aa.ToString());
}
object VariableReturnExampleMethod(int a)
{
if (a == 1)
return "Demo";
else if (a == 2)
return 2;
else if (a == 3)
return true;
else
return null;
}
Edit:
I am in the favor of strongly typed objects and you can implement it easily on .net platform.
if(returnedValue !=null)
{
string currentDataType = returnedValue.GetType().Name;
object valueObj = GetValueByValidating(currentDataType, stringValue);
}
public object GetValueByValidating(string strCurrentDatatype, object valueObj)
{
if (valueObj != "")
{
if (strCurrentDatatype.ToLower().Contains("int"))
{
valueObj = Convert.ToInt32(valueObj);
}
else if (strCurrentDatatype.ToLower().Contains("decimal"))
{
valueObj = Convert.ToDecimal(valueObj);
}
else if (strCurrentDatatype.ToLower().Contains("double") || strCurrentDatatype.ToLower().Contains("real"))
{
valueObj = Convert.ToDouble(valueObj);
}
else if (strCurrentDatatype.ToLower().Contains("string"))
{
valueObj = Convert.ToString(valueObj);
}
else
{
valueObj = valueObj.ToString();
}
}
else
{
valueObj = null;
}
return valueObj;
}
I look on your asks and one is better than second, but last i must rewritting to better understand solution. And this solution skiped long if else stack and replacing it by foreach on Types enum, where we can implement all types what we need. I more like using dynamic, but this is usable too.
Main function GetValueByValidating returned value if is type defined and possible, in other cases return false
Look niranjan-kala this is your main function after rewriting.
///
/// Enum of wanted types
///
public enum Types
{
[ExtendetFlags("int")]
INT,
[ExtendetFlags("decimal")]
DECIMAL,
[ExtendetFlags("double")]
DOUBLE,
[ExtendetFlags("real")]
REAL,
[ExtendetFlags("string")]
STRING,
[ExtendetFlags("object")]
OBJECT,
[ExtendetFlags("null")]
NULLABLE
}
///
/// Cycle by types when in enum exist string reference on type (helper)
///
///
///
public static Types GetCurrentType(string container)
{
foreach (Types t in Enum.GetValues(typeof(Types)))
{
if (container.Contains(t.GetFlagValue()))
{
return t;
}
}
return Types.NULLABLE;
}
///
/// Return object converted to type
///
///
///
///
public static object GetValueByValidating(string strCurrentDatatype, object valueObj)
{
var _value = valueObj != null ? valueObj : null;
try
{
Types _current = _value != null ? GetCurrentType(strCurrentDatatype.ToLower()) : Types.NULLABLE;
switch (_current)
{
case Types.INT:
valueObj = Convert.ToInt32(valueObj);
break;
case Types.DECIMAL:
valueObj = Convert.ToDecimal(valueObj);
break;
case Types.DOUBLE:
valueObj = Convert.ToDouble(valueObj);
break;
case Types.REAL:
valueObj = Convert.ToDouble(valueObj);
break;
case Types.STRING:
valueObj = Convert.ToString(valueObj);
break;
case Types.OBJECT:
break;
case Types.NULLABLE:
throw new InvalidCastException("Type not handled before selecting, function crashed by retype var.");
}
} catch (InvalidCastException ex)
{
Log.WriteException(ex);
valueObj = false;
}
return valueObj;
}

Value of type 'T' cannot be converted to

This is likely a a novice question, but google surprisingly did not provide an answer.
I have this rather artificial method
T HowToCast<T>(T t)
{
if (typeof(T) == typeof(string))
{
T newT1 = "some text";
T newT2 = (string)t;
}
return t;
}
Coming from a C++ background I have expected this to work. However, it fails to compile with "Cannot implicitly convert type 'T' to string" and "Cannot convert type 'T' to string" for both of the above assignments.
I am either doing something conceptually wrong or just have the wrong syntax. Please help me sort this one out.
Thank you!
Even though it's inside of an if block, the compiler doesn't know that T is string.
Therefore, it doesn't let you cast. (For the same reason that you cannot cast DateTime to string)
You need to cast to object, (which any T can cast to), and from there to string (since object can be cast to string).
For example:
T newT1 = (T)(object)"some text";
string newT2 = (string)(object)t;
Both lines have the same problem
T newT1 = "some text";
T newT2 = (string)t;
The compiler doesn't know that T is a string and so has no way of knowing how to assign that.
But since you checked you can just force it with
T newT1 = "some text" as T;
T newT2 = t;
you don't need to cast the t since it's already a string, also need to add the constraint
where T : class
I know similar code that the OP posted in this question from generic parsers. From a performance perspective, you should use Unsafe.As<TFrom, TResult>(ref TFrom source), which can be found in the System.Runtime.CompilerServices.Unsafe NuGet package. It avoids boxing for value types in these scenarios. I also think that Unsafe.As results in less machine code produced by the JIT than casting twice (using (TResult) (object) actualString), but I haven't checked that out.
public TResult ParseSomething<TResult>(ParseContext context)
{
if (typeof(TResult) == typeof(string))
{
var token = context.ParseNextToken();
string parsedString = token.ParseToDotnetString();
return Unsafe.As<string, TResult>(ref parsedString);
}
else if (typeof(TResult) == typeof(int))
{
var token = context.ParseNextToken();
int parsedInt32 = token.ParseToDotnetInt32();
// This will not box which might be critical to performance
return Unsafe.As<int, TResult>(ref parsedInt32);
}
// other cases omitted for brevity's sake
}
Unsafe.As will be replaced by the JIT with efficient machine code instructions, as you can see in the official CoreFX repo:
If you're checking for explicit types, why are you declaring those variables as T's?
T HowToCast<T>(T t)
{
if (typeof(T) == typeof(string))
{
var newT1 = "some text";
var newT2 = t; //this builds but I'm not sure what it does under the hood.
var newT3 = t.ToString(); //for sure the string you want.
}
return t;
}
You will also get this error if you have a generic declaration for both your class and your method. For example the code shown below gives this compile error.
public class Foo <T> {
T var;
public <T> void doSomething(Class <T> cls) throws InstantiationException, IllegalAccessException {
this.var = cls.newInstance();
}
}
This code does compile (note T removed from method declaration):
public class Foo <T> {
T var;
public void doSomething(Class <T> cls) throws InstantiationException, IllegalAccessException {
this.var = cls.newInstance();
}
}
Change this line:
if (typeof(T) == typeof(string))
For this line:
if (t.GetType() == typeof(string))

Categories