Pass varying arguments to unknown form at runtime - c#

I use the following code to call and open a form at runtime (sourced from this forum). The name of the form depends on user input:
// Method
private void ShowForm(string formToCall)
{
Type type = Type.GetType("MyForms." + formToCall);
var form = Activator.CreateInstance(type) as Form;
}
// Call
ShowForm("StationDef");
Now, some forms take arguments and some not. I can add a parameter with a null default value to the ShowForm() method which will then only change when an argument actually gets passed, but I cannot figure out how to change the ShowForm() code to accept an argument in that case.
Something like this does not work:
private void ShowForm(string formToCall, object arg = null)
{
Type type = Type.GetType("MyForms." + formToCall);
var form = Activator.CreateInstance(type) as Form(arg);
}
Any help will be appreciated.

Maybe try something like:
private void ShowForm(string formToCall, object[] args)
{
Type type = Type.GetType("MyForms." + formToCall);
var form = Activator.CreateInstance(type, args) as Form;
}
You can even make it more "friendly" like this
private void ShowForm(string formToCall, params object[] args)
And use it like this:
ShowForm("MyForm", arg1, arg2);

This won't work because as requires a type name, not a constructor-call.
var form = Activator.CreateInstance(type) as Form(arg);
What you can do instead is passing your arguments to the CreateInstance-method like so:
var form = Activator.CreateInstance(type, arg) as Form;
I'd suggest you parse that arg to object so you do not interfere with other overloaded versions of CreateInstance.
Further Reading

Related

Calling a function from other class using Invoke

So what i am trying to do is ;
1) I am getting a string input from user.
2) I am searching the system if project contains a function with the same name of user input.
3) If i find a function with the same name of input i am trying to execute / invoke it.
4) Usually this function is placed into another class , so i tried to create instance of class using Activators but invoke function still fails.
5) Invoke function gives me error ;
Can not invoke method : (methodName) method could not be called !
Here is the code that i am currently working on ;
public void Execute()
{
// If we are only looking for function inputs.
if (!m_canReadCls)
{
// If there is already a class linked into Developer Console.
if (s_linkedType != null)
{
MethodInfo[] tmp = ReflectionExtensions.GetFunctions(s_linkedType);
// Using linear search algorithm for executing functions.
// Need to optimize it !
if (tmp!= null)
{
string funcName = m_uProps.m_inptField.text;
int i;
for (i = 0 ;i < tmp.Length;i++)
{
if ( tmp[i].Name == funcName)
{
var instance = Activator.CreateInstance( s_linkedType);
MethodInfo m = instance.GetType().GetMethod( funcName);
Invoke(m.Name, 0.0f);
Reset();
}
}
}
}
}
}
Any help is great , thanks :-)
See Microsoft help here You can call m.Invoke. or see this post
In more details
public object Invoke(
object obj,
object[] parameters
)
and
Type magicType = Type.GetType("MagicClass");
ConstructorInfo magicConstructor = magicType.GetConstructor(Type.EmptyTypes);
object magicClassObject = magicConstructor.Invoke(new object[]{});
// Get the ItsMagic method and invoke with a parameter value of 100
MethodInfo magicMethod = magicType.GetMethod("ItsMagic");
object magicValue = magicMethod.Invoke(magicClassObject, new object[]{100});

Attach Generic method event handler with unknow type

I need to attach this handler to a RadListView Column creation, by adding a DataSource to the control.
public void GenericColumnCreatingHandler<T>(object sender, ListViewColumnCreatingEventArgs e)
{
e.Column.Visible = BaseEntity<int>.MemberVisibility<T>
(e.Column.FieldName, TelerikPropertyVisibilityAttribute.VisibilityTypeEnum.BaseDetails);
e.Column.HeaderText = CaricaTestoLocale(e.Column.HeaderText, "Col_" + e.Column.HeaderText);
e.Column.BestFit();
e.Column.AutoSizeMode = ListViewBestFitColumnMode.AllCells;
}
My problem is that I need to perform the handler attach from this other generic method:
private void PopulateRecord(TipoTabellaBase tipo)
{
Type generic = typeof(CommonTableService<>);
Type[] typeArgs = { tipo.Tipo };
var constructed = generic.MakeGenericType(typeArgs);
var instance = Activator.CreateInstance(constructed);
if (instance == null)
return;
MethodInfo getEntities = constructed.GetMethod("GetEntitiesWithNoParameters");
//getEntities = getEntities.MakeGenericMethod(typeArgs);
var result = (IEnumerable<BaseEntity<int>>)getEntities.Invoke(instance, null);
lvRecords.ColumnCreating += base.GenericColumnCreatingHandler<BaseEntity<int>>;
lvRecords.DataSource = result;
BestFit(lvRecords);
generic = null;
typeArgs = null;
constructed = null;
getEntities = null;
instance = null;
}
The problematic row is this one:
lvRecords.ColumnCreating += base.GenericColumnCreatingHandler<BaseEntity<int>>
because BaseEntity is EF base type for all Entities, but this is not enought for the BaseEntity.MemberVisibility method; this method need to know the exact entity type to set the visible properties (and, of course, grid column) based on specific custom attribute on that.
Question is: how I can call base.GenericColumnCreatingHandler where T is TipoTabellaBase tipo.Tipo (type) without knowing type at design time?
Any help would be very appreciated!
Thanks is advance.
Daniel
Please note that this solution is untested.
You will have to instantiate the strongly-typed version of base.GenericColumnCreatingHandler<T> at runtime.
From your code, I figure you already know how to obtain a MethodInfo instance for a given method. You will need to get the MethodInfo for base.GenericColumnCreatingHandler<T> (let's call it genericMethodInfo).
Then, you can create a strongly-typed version of that method with MakeGenericMethod:
MethodInfo typedMethodInfo = genericMethodInfo.MakeGenericMethod(new[] {
typeof(BaseEntity<int>)
});
Once that is done, you need to invoke CreateDelegate to obtain something that you can assign to the ColumnCreating event, as described here or here:
lvRecords.ColumnCreating +=
(ListViewColumnCreatingEventHandler)typedMethodInfo.CreateDelegate(
typeof(ListViewColumnCreatingEventHandler), this);
EDIT: Replaced base with this in the last code sample. In case an inherited method is specifically required, this has to be taken care of while retrieving genericMethodInfo.

Writing extensions for inherited types

I'm trying to write a couple extensions for some types I'm working with. The base type is 'InputField'. 'ListField' inherits from 'InputField'. I'll show what I'm trying to do:
public static void LoadInputField(this InputField input, CustomField field)
{
SetValues(ref input, field);
}
public static void LoadInputField(this ListField input, CustomField field)
{
SetValues(ref input, field);
var optionItems = (from o in field.CustomFieldOptions
select new ListItem(o.OptionLabel, o.CustomFieldOptionId.ToString()));
input.AddChoices(optionItems.ToList());
}
private static void SetValues(ref InputField input, CustomField field)
{
input.CustomFieldId = field.CustomFieldId;
input.ResponseTitle = field.ColumnName;
input.Prompt = field.ColumnCaption;
input.DisplayOrder = field.SortOrder;
input.Required = !string.IsNullOrEmpty(field.ColumnRequiredMessage);
input.ErrorClass = "text-danger";
if (input.Required)
input.RequiredMessage = field.ColumnRequiredMessage;
}
The extension for the ListField type errors at SetValues(ref input, field);. The message says, 'The 'ref' argument type doesn't match parameter type.'
Perhaps this isn't the best way to do this, but I'm open to options.
You can cast it on a local variable before you call the method:
InputField inputField = (InputField)input;
SetValues(ref inputField, field);
Apart from that i don't understand why you need ref, it works without casting if it's not ref. C# requires that any ref parameters be of the exact type.
As per the suggestions in the comments, I dropped ref and the code works.

C# generic delegate that accept function without arguments

I've created a generic delegate and I want to assign to it a function without any arguments.
Is it possible?
Here is what I tried so far:
class Program
{
public delegate void TemplateDel<T>(T item);
public static void fWriteLetters(char[] p_cLetters)
{
for (int i = 0; i < p_cLetters.Length; i++)
Console.WriteLine(p_cLetters[i]);
}
void fNoArg()
{
Console.WriteLine("No arguments!");
}
static void Main(string[] args)
{
TemplateDel<char[]> l_dWriteLeters = new TemplateDel<char[]>(fWriteLetters);
TemplateDel<void> l_dNoArg = new TemplateDel<void>(fWriteLetters);
}
}
the last line of code doesn't compile...
No it is not possible.void is only valid in return types.You can't use it as a type in other contexts. (except the unsafe context)
You need add another overload for your delegate.
public delegate void TemplateDel();
Or simply use an Action.
As Selman22 notes in the other answer:
No it is not possible.
But there is another way, use a lambda to throw away the argument:
TemplateDel<bool> l_dNoArg = new TemplateDel<bool>(_ => fWriteLetters);
(Using _ as the identifier here matches F#'s wildcard – ignore this argument – syntax.)
While not helpful here, this kind of wrapper is helpful when arguments are not interested in are passed and saves writing an extra member just to ignore or re-arrange arguments.

How to call the correct overloaded function at runtime?

How do I call the correct overloaded function given a reference to an object based on the actual type of the object. For example...
class Test
{
object o1 = new object();
object o2 = new string("ABCD");
MyToString(o1);
MyToString(o2);//I want this to call the second overloaded function
void MyToString(object o)
{
Console.WriteLine("MyToString(object) called.");
}
void MyToString(string str)
{
Console.WriteLine("MyToString(string) called.");
}
}
what I mean is there a better option than the following?
if(typeof(o) == typeof(string))
{
MyToString((string)o);
}
else
{
MyToString(o);
}
May be this can be done using reflection?
Ok as soon as I hit post I remembered this can indeed be done using reflection...
var methInfo = typeof(Test).GetMethod("MyToString", new Type[] {o.GetType()});
methInfo.Invoke(this, new object[] {o});
You could just use ternary operators to code this using a single clean line of code:
MyToString(o is string ? (string)o : o);
Why not have a toString() function in the actual object itself? That way you can call myObj.toString() and the relative output is given. Then you don't have to do any comparisons.

Categories