2016-02-02 2 views
1

Можно ли возвращать объект типаC# возвращенная общий тип без параметра типа во время выполнения

IModel<T> 

, не зная тип параметра?

объекты хранятся в словаре, с типом в качестве ключа и объектом с IModel (базовый интерфейс до IModel<T>), реализованный в качестве значения. Интерфейс IModel<T> наследуется от IModel, но для выполнения полного действия мне нужен объект IModel<T>. T должен иметь интерфейс IFactoryItem.

но первый код:

public IModel<T> GetModel<T>() where T : IFactoryItem 
    { 
     Type tmpType = typeof(T); 
     if (!_allModelsByType.ContainsKey(tmpType)) 
       return null; 

     return (IModel<T>)_allModelsByType[tmpType]; 
    } 

я подумал о решении, как

общественного IModel GetModel (тип Т) и обертку, чтобы бросить его на правильный тип.

Я надеюсь, что я не совсем ошибаюсь. это мой первый вопрос.

+1

Ваш метод выглядит прекрасно, предполагая, что значения в словаре выстраиваются в линию с ключ типа. В чем проблема? –

ответ

1

Если ваш вопрос заключается в том, чтобы вернуть экземпляр IModel<T>, но вы не знаете, что T во время компиляции, только то, что оно всегда происходит от IFactoryItem то:

Если вы не используете T в входной метод, и T класс можно использовать ковариации:

public interface IModel<out T> where T : class 
{ 
    T Value { get; } 
} 

public class Model<T> : IModel<T> where T : class 
{ 
    public T Value { get; set; } 
} 


class Program 
{ 
    static void Main(string[] args) 
    { 
     var foo = new Model<string>() 
     { 
      Value = "hello world", 
     }; 

     IModel<object> boo = foo; 

     Console.WriteLine(boo.Value); 
    } 
} 

Таким образом, вы можете обойти IModel<IFactoryItem>, а не IModel<T>

Если вам нужны типы значений, хотя, или вы не можете использовать ковариации, то в идеале вы должны были бы (как вы предлагаете) второй, не универсальный интерфейс, который предоставляет IModel любые значения, как object

public interface IModel 
{ 
    object Value { get; } 
} 

public class Model<T> : IModel, IModel<T> 
{ 
    public T Value { get; set; } 
    object IModel.Value => Value; 
} 

Если ваш вопрос как сделать экземпляр Model<T>, когда вы только знаете тип во время выполнения, то его:

var someType = typeof (SomeFactoryItem); 
var instance = Activator.CreateInstance(typeof (Model<>).MakeGenericType(someType)); 

вы должны либо вернуть IModel или, если вы можете использовать covarience, IModel<IFactoryItem>

0

Возможно ли вернуть объект типа IModel<T> без знания параметра типа?

Технически нет, но я думаю, что на самом деле это было задано с небольшим недоразумением. Тип Tis знаю, это просто общий - на самом деле так хорошо известно, что он даже ограничен. Обратите внимание на where T : IFactoryItem, это означает, что все, что пытается выполнить либо функции AddModel, либо GetModel, должно быть чем-то, что реализует интерфейс IFactoryItem. Если вы пытаетесь написать что-то, которое вызывает какие-либо методы, и передает в него что-либо иное, кроме реализации интерфейса IFactoryItem, оно даже не будет компилироваться.

Пожалуйста, рассмотрите приведенный ниже код, а именно: fetch - фактически тот же объект, что и переменная model, которая была добавлена!

class Program 
{ 
    static void Main() 
    { 
     var test = new Test(); 
     var model = new Model(); 
     test.AddModel(model); 
     var fetch = test.GetModel<FactoryItem>(); 

     Console.WriteLine(fetch == model 
           ? "It does in fact work..." 
           : "Uh, that was supposed to work?"); 
     Console.ReadLine(); 
    } 

    public class Test 
    { 
     private readonly Dictionary<Type, object> _allModelsByType; 

     public Test() 
     { 
      _allModelsByType = new Dictionary<Type, object>(); 
     } 

     public void AddModel<T>(IModel<T> model) where T : IFactoryItem 
     { 
      _allModelsByType.Add(typeof(T), model); 
     } 

     public IModel<T> GetModel<T>() where T : IFactoryItem 
     { 
      var tmpType = typeof(T); 
      return _allModelsByType.ContainsKey(tmpType) 
       ? _allModelsByType[tmpType] as IModel<T> 
       : null; 
     } 
    } 
} 

internal class FactoryItem : IFactoryItem { } 

internal class Model : IModel<FactoryItem> 
{ 
    public FactoryItem Value { get; set; } 
} 

internal interface IFactoryItem { } 

internal interface IModel<T> where T : IFactoryItem 
{ 
    T Value { get; set; } 
} 

Запуск этой программы выведет «Это действительно фактически работают ...»

<iframe width="100%" height="750" src="https://dotnetfiddle.net/Widget/J26ETn" frameborder="0"></iframe>

Смежные вопросы