Кастинг <string>к действию <object> - PullRequest
3 голосов
/ 03 ноября 2010

Мне нужно разыграть Action<string> до Action<object>. Хотя это вообще небезопасно, в моем случае он всегда будет вызываться со строкой. Я получаю эту ошибку:

Unable to cast object of type 'System.Action<code>1[System.String]' to type 'System.Action 1 [System.Object]».

Есть какие-нибудь подсказки? Отражение - это честная игра. Перенос одного делегата в другого - это не .

UPDATE: Я создал новый вопрос на Создание действующего открытого делегата для установщика или получателя свойства с более подробным объяснением моей проблемы и решением с использованием переноса, который я хочу улучшить в

Ответы [ 4 ]

6 голосов
/ 03 ноября 2010

Во-первых, это не безопасно.То, что может принимать любую строку, не может (обязательно) принимать любой объект.Вспомните пример метода:

void method(String s)
{
  s.Trim();
}

Очевидно, что это было бы неудачно, если бы s был объектом без Trim.

Технически это означает, что Action противоречиво для T. Вы могли быприсвойте Action<string> гипотетической ссылке Action<SubclassString>, но string нельзя разделить на подклассы.

Это правда, что C # допускает регулярные небезопасные приведения (например, от object к string) нариск InvalidCastException.Тем не менее, они решили не реализовывать инфраструктуру для небезопасных приведений делегатов.

РЕДАКТИРОВАТЬ: Я не знаю, как сделать это без оболочки.

1 голос
/ 13 августа 2016

Извините за поздний удар, но я искал способ сделать это сегодня и наткнулся на этот пост. На самом деле, единственный простой способ сделать это - обернуть Action<string> в новый Action<object>. В моем случае я помещал свои действия в параллельный словарь, а затем извлекал их по типу.

По сути, я обрабатываю очередь сообщений, в которой можно определить действия для обработки сообщений с определенным типизированным вводом.

ConcurrentDictionary<Type, Action<object>> _actions = new ConcurrentDictionary<Type, Action<object>>();
Action<string> actionStr = s => Console.WriteLine(s);

var actionObj = new Action<object>(obj => { 
  var castObj = (V)Convert.ChangeType(obj, typeof(V)); actionStr(castObj); 
} );

_actions.TryAdd(typeof(string), actionObj);
1 голос
/ 03 ноября 2010

Я знаю, что ваше сообщение указывает, что перенос в другого делегата не вариант, но, к сожалению, это действительно ваш лучший выбор здесь. CLR просто не допускает приведение между делегатами в этом направлении. Никакое количество отражения не может исправить это либо. Можете ли вы уточнить, почему это не вариант?

Причина в том, что это создает проблемы безопасности типов, потому что вызывающая сторона может передать любой объект в Action<object>, в то время как Action<string> может обрабатывать только строки. Даже если ваш код только передает string, CLR не может гарантировать это и, следовательно, не допускает небезопасного преобразования.

Следующий лучший вариант, о котором я могу подумать, - это изменить исходный метод, который обернут в Action<string>, с параметра типа string на параметр, который принимает object. Затем пусть он вручную проверит тип string. Например

// Original Version
void Method(string str) {
  // Operate on the string
}

// Modified version
void Method(object obj) { 
  string str = (string)obj;
  // operate on the string
}
0 голосов
/ 03 ноября 2010

Поскольку рефлексия - честная игра, я предложу следующее.Вы можете избавиться от проблемы приведения, если будете следить за Object, MethodInfo и, возможно, параметром, с которым вы будете работать.Пример того, как работает эта концепция, выглядит следующим образом:

Action<string> s;
Action<object> o;

object sTarget = s.Target;
object oTarget = o.Target;

MethodInfo sMethod = s.Method;
MethodInfo oMethod = o.Method;

// Time to invoke in a later time.
sMethod.Invoke(sTarget, new object[] { strVal });
oMethod.Invoke(oTarget, new object[] { objVal });

Единственная опасность, связанная с этим, заключается в том, что неправильный тип параметра будет выполнен против неправильного метода.Вам может понадобиться сделать некоторые бухгалтерии здесь, чтобы предотвратить это.Но в вашем случае, поскольку есть гарантия, что строка будет передана (и поскольку строка всегда является объектом), это всегда должно быть успешным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...