Можно ли применить переменную к типу, хранящемуся в другой переменной?

17

Это то, что мне нужно сделать:

object foo = GetFoo();
Type t = typeof(BarType);
(foo as t).FunctionThatExistsInBarType();

Можно ли сделать что-то подобное?

    
задан Marek Grzenkowicz 21.01.2009 в 11:36
источник
  • Откуда вы знаете, что это строка, которую вы хотите в левой части равенства в последней строке вашего примера? Другими словами, что вы собираетесь делать с баром, что означает, что вы не можете использовать «object bar = (object) foo;» ? –  Martin Brown 21.01.2009 в 13:29
  • Я этого не делаю, строка была всего лишь примером. Я отредактировал фрагмент. –  Marek Grzenkowicz 21.01.2009 в 13:58

5 ответов

13

Нет, вы не можете. C # не реализует печатание утки .

Вы должны реализовать интерфейс и применить его.

(Однако есть попытки сделать это. Посмотрите Проект Duck Typing для пример.)

    
ответ дан Quassnoi 21.01.2009 в 11:39
источник
  • Да, вы можете. Посмотрите на ответ GvS :-) –  Rune Grimstad 21.01.2009 в 12:02
  • Вам по-прежнему необходимо реализовать интерфейс (в этом случае можно отключить IConvertible), а также знать, какой тип заносится заранее. –  Quassnoi 21.01.2009 в 12:11
  • Я пометил этот ответ в качестве принятого, так как я использовал совет Кваснои и реализовал интерфейс, чтобы отбросить его, но ответы GvS и shuggycouk тоже великолепны. –  Marek Grzenkowicz 21.01.2009 в 15:15
20

Вы можете использовать метод Convert.ChangeType .

object foo = GetFoo(); 
Type t = typeof(string);
string bar = (string)Convert.ChangeType(foo, t);
    
ответ дан GvS 21.01.2009 в 11:58
источник
  • Это полезно, только если объект реализует IConvertible –  Quassnoi 21.01.2009 в 12:03
  • Я использовал строку только в качестве примера. Проблема в том, что я не знаю тип цели, поэтому я не могу выполнить этот xyz bar = (xyz) Convert.Change ... cast. –  Marek Grzenkowicz 21.01.2009 в 12:33
  • Convert.ChangeType не кастинг, это преобразование. т. е. создание нового объекта указанного типа. Если вы хотите, чтобы произнести ICollection, это не сработает. –  Hoots 29.07.2014 в 14:08
4

Ваш исходный вопрос был ошибочным в том, что вы просите обработать переменную как тип, который неизвестен во время компиляции, но обратите внимание, что у вас есть строка, определенная с левой стороны, когда вы объявляете свою переменную. C # с 3.5 статически типизирован.

Как только динамика доступна, вы можете сделать что-то вроде этого:

dynamic foo = GetFoo();
foo.FunctionThatExistsInBarType(); 

Если вы не знаете, что такое тип, но вы знаете, он всегда будет поддерживать метод экземпляра FunctionThatExistsInBarType ();

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

// any of these can be determined at runtime
Type t = typeof(Bar);
string methodToCall = "FunctionThatExistsInBarType";
Type[] argumentTypes = new Type[0];
object[] arguments = new object[0];
object foo;
// invoke the method - 
// example ignores overloading and exception handling for brevity
// assumption: return type is void or you don't care about it
t.GetMethod(methodToCall, BindingFalgs.Public | BindingFlags.Instance)
    .Invoke(foo, arguments);
    
ответ дан ShuggyCoUk 21.01.2009 в 13:05
источник
  • Тип строки был только примером (не очень хорошим); Я отредактировал фрагмент кода, надеюсь, теперь он станет понятнее. –  Marek Grzenkowicz 21.01.2009 в 14:00
  • Вправо - для этого (pre dynamic) вы должны использовать отражение. Я отредактирую, чтобы принять это во внимание –  ShuggyCoUk 21.01.2009 в 14:13
3

Поскольку динамика была добавлена ​​к c #, я думаю, что мы можем сделать это следующим образом:

class Program {
    static void Main(string[] args) {
        List<int> c = new List<int>(); 
        double i = 10.0;
        Type intType = typeof(int);
        c.Add(CastHelper.Cast(i, intType)); // works, no exception!
    }
}

class CastHelper {
    public static dynamic Cast(object src, Type t) {
        var castMethod = typeof(CastHelper).GetMethod("CastGeneric").MakeGenericMethod(t);
        return castMethod.Invoke(null, new[] { src });
    }
    public static T CastGeneric<T>(object src) {
        return (T)Convert.ChangeType(src, typeof(T));
    }
}
    
ответ дан rmrfhome 11.02.2016 в 10:17
источник
  • Это работало как шарм, где других решений не было. –  BrotherOdin 01.11.2017 в 14:00
  • Отлично, спасибо! –  Stark 15.11.2017 в 11:26
0

При условии, что вы знаете все необходимые типы во время компиляции, утиная печать (возможно):

class BarFoo {}
class Foo {}
class Bar {}

class Program
{
    static void Main( )
    {
        var foo = new Foo( );
        var bar = new Bar( );
        var barfoo = new BarFoo( );

        Console.WriteLine(DoStuff(foo));
        Console.WriteLine(DoStuff(bar));
        Console.WriteLine(DoStuff(barfoo));

    }

    static string DoStuff(Foo foo) { return "DoStuff(Foo foo)"; }
    static string DoStuff(Bar bar) { return "DoStuff(Bar bar)"; }
    static string DoStuff(Base fb) { return "DoStuff(object fb)"; }
}

Вывод:

Dostuff(Foo foo)
Dostuff(Bar bar);
DoStuff(object fb);

Если вы в конечном итоге реализуете множество методов, которые в основном делают то же самое, подумайте о внедрении интерфейса.

    
ответ дан Marcus Hansson 23.07.2013 в 11:36
источник
  • Ух .. Четыре года спустя .. Ну ладно. –  Marcus Hansson 23.07.2013 в 11:37
  • Это не утка. Это полиморфизм (применяется к функции DoStuff). –  Tomas Lycken 24.10.2014 в 16:06