Forum

PureSourceCode.com Forum
Create element from...
 
Share:
Notifications
Clear all

Create element from interface

1 Posts
1 Users
0 Likes
986 Views
0
Topic starter

I'm trying to generate at run-time with Blazor a survey based on a definition in a Json file.

I have an interface for all element called IElement

public interface IElement
{
    public string? ElementType { get; set; }
    public string? Name { get; set; }
}

Then, I have few classes that inherit from it, for example

public class Textbox : IElement
{
    [JsonPropertyName("type")]
    public virtual string? Type { get; set; }
    [JsonPropertyName("name")]
    public string? Name { get; set; }

    [JsonPropertyName("text")]
    public string? Text { get; set; }
}

public class Radiobutton : IElement
{
    [JsonPropertyName("type")]
    public virtual string? Type { get; set; }
    [JsonPropertyName("name")]
    public string? Name { get; set; }

    [JsonPropertyName("choises")]
    public List<string> Choises = new List<string>();
}

The list of components to display is contained in a list called ElementData. To show the right HTML component, the interface, I use a switch like that (it is working):

foreach (var el in ElementData)
{
    dynamic newElement = null;
    switch (el.ElementType)
    {
        case ElementType.Checkbox:
            Checkbox data = el as Checkbox;
            Checkbox test1 = new Checkbox();
            test1.CopyTo(data, new[] { "Parent", "Index", "QuestionNumber", "Name" });
            newElement = test1;
            break;
        case ElementType.Textbox:
            newElement = el.CreateElement<Textbox>();
            Textbox data2 = el as Textbox;
            Textbox test2 = new Textbox();
            test2.CopyTo(data2, new[] { "Parent", "Index", "QuestionNumber", "Name" });
            newElement = test2;
            break;
    }
}

This code is not very elegant, and for each component I have to change only the type like Checkbox or Textbox. I wrote a generic code in T to replace those lines

public class CreateService<T> where T : class
{
    public T CreateElement(IElement el)
    {
        T data = (T)el;
        T test1 = default(T);
        CopyTo(test1, data, new[] { "Parent", "Index", "QuestionNumber", "Name" });
        return test1;
    }

    public T CopyTo<T, S>(T target, S source, string[] propertyNames)
    {
        if (source == null)
            return target;

        Type sourceType = typeof(S);
        Type targetType = typeof(T);
        BindingFlags flags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance;

        PropertyInfo[] properties = sourceType.GetProperties();
        foreach (PropertyInfo sPI in properties)
        {
            if (!propertyNames.Contains(sPI.Name))
            {
                PropertyInfo tPI = targetType.GetProperty(sPI.Name, flags);
                if (tPI != null && tPI.CanWrite && tPI.PropertyType.IsAssignableFrom(sPI.PropertyType))
                {
                    tPI.SetValue(target, sPI.GetValue(source, null), null);
                }
            }
        }

        return target;
    }
}

but it is not working at all. The error I get is

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: Non-static method requires a target.

System.Reflection.TargetException: Non-static method requires a target.

at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)

at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)

at System.Reflection.PropertyInfo.SetValue(Object obj, Object value, Object[] index)

How can I implement correctly the function to create a new element?

1 Answer
0
Topic starter

I found a solution to my question. I created a function that returns a dynamic value.

public static dynamic CreateElement(this IElement element) {
    dynamic newElement = null;

    \\ ...
    return newElement;
}

With this function, I define a variable in the newElement variable and its type could be anything. Then, the function returns this newElement.

Share: