Отражение C # Приведение к типу экземпляра для ex var o = (typeof (this)) anotherobj - PullRequest
0 голосов
/ 23 февраля 2012
public class SomeClass<T>
{
    public T DoSomething()
    {
        var obj = Activator.CreateInstance(this.GetType());
        // Do Things
        return (T)obj;
    }
}

public class DoStuff : SomeClass<DoStuff>
{
}

var ds = new DoStuff();
ds.DoSomething();

это работает, но в этом сценарии:

public abstract class AbstractStuff : SomeClass<AbstractStuff>
{
}

public class DoStuff : AbstractStuff
{
}

var ds = new DoStuff();
ds.DoSomething();

выдает ошибку, не может создать экземпляр абстрактного класса, и я понимаю, я хочу сделать что-то вроде этого:

public class SomeClass<T>
{
    public T DoSomething()
    {
        var obj = Activator.CreateInstance(this.GetType());
        // Do Things
        return (my not know how to get this casting type)obj;
    }
}

я попробовал return (typeof (this)) obj;

и не работает, какая-то идея? Thanx

К сожалению: я забыл объявить AbstractStuff как абстрактный (исправлено)

Ответы [ 3 ]

3 голосов
/ 23 февраля 2012

Это работает для меня

public abstract class AbstractClass<T> where T : new()
{
    public T DoSomething()
    {
        var obj = new T();

        // Do Things

        return obj;
    }
}

public class DoStuff : AbstractClass<DoStuff>
{
}

var ds = new DoStuff();
ds.DoSomething();

и так же изменяется исходный код следующим образом:

public T DoSomething()
{
    var obj = Activator.CreateInstance(typeof(T));

    // Do Things

    return (T)obj;
}

так что мы создаем экземпляр неабстрактного производного класса, а не абстрактного базового класса.

1 голос
/ 23 февраля 2012

Рассмотрим этот пример из вашего вопроса ...

public class SomeClass<T>
{
    public T DoSomething()
    {
        var obj = Activator.CreateInstance(this.GetType());
        // Do Things
        return (T)obj;
    }
}

... и тот случай, когда у вас есть

public abstract class AbstractStuff : SomeClass<AbstractStuff> { }
public class DoStuff : AbstractStuff { }

Если вы замените параметр типа аргументом, вы получите это для DoSomething():

public AbstractStuff DoSomething()
{
    var obj = Activator.CreateInstance(this.GetType());
    // Do Things
    return (AbstractStuff)obj;
}

Теперь давайте немного изменим рефакторинг для простоты «отладки» и добавим номера строк:

1 public AbstractStuff DoSomething()
2 {
3     var type = this.GetType();
4     var obj = Activator.CreateInstance(type);
5     // Do Things
6     return (AbstractStuff)obj;
7 }

Если вы вызовете этот метод для экземпляра DoStuff и прервитесь на строке 4, вы увидите, что type - это DoStuff; если вы прервете строку 6, вы увидите, что тип времени выполнения obj также равен DoStuff. Конечно, приведение этого объекта к AbstractStuff будет успешным (и приведение даже не требуется), потому что всегда есть неявное преобразование ссылки из любого ссылочного типа в его базовый тип.

Теперь давайте рассмотрим сообщение об ошибке, о котором вы сообщаете: «невозможно создать экземпляр абстрактного класса». Что это говорит нам? Он говорит, что по какой-то причине, когда вы вызываете Activator.CreateInstance, вы передаете ссылку на тип AbstractStuff.

Похоже, пример кода, который вы нам дали, не точный. GetType() никогда не сможет вернуть абстрактный тип, , потому что тип времени выполнения объекта никогда не может быть абстрактным типом. Другими словами, невозможно иметь экземпляр абстрактного типа.

На самом деле, описанное вами поведение будет ожидаемым, если у вас будет строка ...

var obj = Activator.CreateInstance(typeof(T));

... а не ...

var obj = Activator.CreateInstance(this.GetType());

Вы уверены, что это не так?

1 голос
/ 23 февраля 2012

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

public class Foo : SomeAbstractClass<Bar>
...

Foo foo = new Foo();
??? newFoo = foo.DoSomething();

Поскольку Foo расширяет SomeAbstractClass<Bar>, ваш первый пример будет ожидать возврата Bar, но вы, похоже, надеетесь вернуть Foo,Это было бы возможно , если Bar расширяется Foo.

Вы пытаетесь сделать что-то более подобное?

void Main()
{
    DoStuff doStuff = new DoStuff();
    DoStuff doStuff2 = doStuff.DoSomething();
}

public abstract class SomeClass<T> 
    where T : SomeClass<T>, new()
{
    public T DoSomething()
    {
        return new T();
    }
}

public class DoStuff : SomeClass<DoStuff>
{

}
...