пользовательский тип данных, использующий неявный оператор, не работающий с отражением - PullRequest
0 голосов
/ 23 марта 2020

Я создал пользовательский тип данных с использованием неявного оператора, ниже приведен пример кода. Когда я устанавливаю жестко запрограммированное значение для своего пользовательского типа данных, он работает как положено, но при установке значения используется ошибка преобразования с отбрасыванием отражения. (System.ArgumentException: объект типа 'System.String' не может быть преобразован в тип 'TF.DataType.TFDiplay'. ')

Может кто-нибудь помочь мне, что мне нужно изменить, чтобы хорошо работать с отражениями

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TF.DataType
{
    public class TFDiplay 
    {
        public TFDiplay() { }
        public TFDiplay(object value, string text) { Value = value; Text = text; }
        public TFDiplay(object value)
        {
            Value = value;
        }

        public static implicit operator TFDiplay(string value)
        {
            var result = new TFDiplay()
            {
                Value = value
            };
            return result;
        }

        public static implicit operator TFDiplay(int value)
        {
            var result = new TFDiplay()
            {
                Value = value
            };
            return result;
        }


        public object Value { get; set; }

        public string Text { get; set; }


    }
}

class Program
{
    static void Main(string[] args)
    {

        TFDiplay tFDiplay;

        tFDiplay = "ss"; //Working as expected
        tFDiplay = 1; //Working as expected

        testDatatype t = new testDatatype();

        Type s = t.GetType();

        PropertyInfo p = s.GetProperty("Flag");

        p.SetValue(t, "ss");  //Throwing error



    }

    public class testDatatype
    {
        public TFDiplay Flag { get; set; }
    }
}

Ответы [ 3 ]

1 голос
/ 23 марта 2020

А вот и другой подход, использующий пользовательский Binder (https://docs.microsoft.com/en-us/dotnet/api/system.reflection.binder?view=netframework-4.8)

Я сомневаюсь, что это то, что вы ищете, но, тем не менее, это может помочь. Здесь мы просто реализуем переопределение ChangeType.

public class TFDisplayBinder : Binder
{
    public override object ChangeType(object value, Type type, System.Globalization.CultureInfo culture)
    {
        if (value is string)
        {
            return (TFDiplay)(string)value;
        }
        if (value is int)
        {
            return (TFDiplay)(int)value;
        }
        throw new NotImplementedException();
    }

    public override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, System.Globalization.CultureInfo culture)
    {
        return Type.DefaultBinder.BindToField(bindingAttr, match, value, culture);
    }

    // You can implement the other abstract methods the same way, or just throw
    // NotImplementedException for they are not invoked in our case
}

А при назначении с помощью отражения:

    testDatatype t = new testDatatype();

    Type s = t.GetType();

    PropertyInfo p = s.GetProperty("Flag");

    p.SetValue(t, "ss", BindingFlags.Default, new TFDisplayBinder(), null, null);
1 голос
/ 23 марта 2020

Проблема в том, что вы не можете присвоить строку типу TFDiplay через отражение. Reflection не использует неявные преобразователи. неявные преобразователи являются типом компиляции. отражение - время выполнения.

Выделение:

TFDiplay tFDiplay;

tFDiplay = "ss"; //Working as expected
tFDiplay = 1; //Working as expected

Неявные операторы делают всю работу за вас. Каждый раз, когда для tFDiplay назначается строка или int, вызывается оператор, запускается новый TFDisplay. Поэтому вызов оператора для существующего объекта бесполезен.

Это также причина, по которой вам не нужно инициировать новый экземпляр при его назначении.

Вот код отражения, который работы:

using System;
using System.Reflection;

namespace ConsoleApp4
{
    class Program
    {
        static void Main(string[] args)
        {
            TFDiplay tFDiplay;

            tFDiplay = "ss"; //Working as expected
            tFDiplay = 1; //Working as expected

            // ----

            // create an instance of testDatatype
            testDatatype testDatatype = new testDatatype();

            Type testDatatypeType = testDatatype.GetType();

            PropertyInfo flagProperty = testDatatypeType.GetProperty("Flag");

            // you need to get the value of the flag..
            var flagInstance = flagProperty.GetValue(testDatatype);

            Type flagType = flagInstance.GetType();

            PropertyInfo valueProperty = flagType.GetProperty("Value");

            valueProperty.SetValue(flagInstance, "ss");  
        }
    }

    public class testDatatype
    {
        // notice that I create an instance here:
        public TFDiplay Flag { get; } = new TFDiplay();
    }

    public class TFDiplay
    {
        public TFDiplay() { }
        public TFDiplay(object value, string text) { Value = value; Text = text; }
        public TFDiplay(object value)
        {
            Value = value;
        }

        public static implicit operator TFDiplay(string value)
        {
            var result = new TFDiplay()
            {
                Value = value
            };
            return result;
        }

        public static implicit operator TFDiplay(int value)
        {
            var result = new TFDiplay()
            {
                Value = value
            };
            return result;
        }


        public object Value { get; set; }

        public string Text { get; set; }


    }
}
0 голосов
/ 23 марта 2020

Чтобы расширить ответ Йеруна:

Неявный оператор генерирует специальный метод, называемый op_Implicit. Чтобы правильно «привести» использование неявного оператора, вы можете вызвать этот метод с помощью отражения:

var op = typeof(TFDiplay).GetMethod("op_Implicit", BindingFlags.Public | BindingFlags.Static, 
    null, new[] { typeof(string) }, null);
tFDiplay = (TFDiplay)op.Invoke(null, new object[] { "ss" });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...