簡體   English   中英

有沒有辦法處理未知的泛型類型?

[英]Is there a way to deal with unknown generic types?

我有這個代碼

public interface IConsumable<T> {
  void Consume(T item);
}

public interface IProducer<T> {
  IConsumable<T> Consumer { get; set; }
  void Produce();
}

public class MyClass : MyType, 
  IConsumable<ISpecifcItem>
{
  public void Consume(ISpecificItem item) { ... }
}

public class MySpecificItemProducer
  : IProducer<ISpecificItem> {
  public IConsumable<ISpecificItem> Consumer { get; set; }
  public void Produce() {
    ISpecificItem myItem = new MyVerySpecificItem();
    Consumer.Consume(myItem);
  }
}

然后,我有一個采用任何MyType的控制器,發現它實現的所有IConsumable<>類型並獲取通用類型參數的類型。 使用此類型列表,它可以發現實現IProducer<TParam>所有生產者。 這並不困難:

var consumerTypes =
    myType.GetType().GetInterfaces()
    .Where(x => x.IsGenericType)
    .Where(x => x.GetGenericTypeDefinition() ==
        typeof(IConsumable<>));

  if (consumerTypes.Any()) {
    var instanceTypes = consumerTypes
      .Select(x => x.GetGenericArguments().First())
      .Select(x => typeof(IProducer<>).MakeGenericType(x));
    // for each of those types discover classes where 
    // it assignable from
    // and instantiate the class using the Activator
  }

但是問題是,如何設置生產者的Consumer屬性? 生產者實例對我來說是一個對象,我不能將其IProducer<T>轉換為IProducer<T> ,因為我不能像變量一樣使用T。

我可以通過反射producerInstance.GetType().GetProperty("Consumer").SetValue(producerInstance, consumerInstance, null); 但我想知道是否還有另一種方法?

有趣的是,這在運行時失敗了:

MyClass consumerInstance;
dynamic test = producerInstance;
test.Consumer = consumerInstance;

它抱怨consumerInstance的類型與屬性的類型不兼容。

編輯:僅當consumerInstance也是動態的時,動態示例才起作用,例如:

dynamic testC = consumerInstance;
dynamic testP = producerInstance;
testP.Consumer = testC;

不幸的是,如果不重構您提供的代碼,就無法在沒有更多思考的情況下解決問題(如您所做的那樣)。 但是,可以在設置使用者屬性之前使用反射,如果它使您更容易理解。

var method = GetType().GetMethod("Process");
var genericType = interfaceType.GetGenericArguments().First();
var invocable = method.MakeGenericMethod(genericType);

invocable.Invoke(this, new object[] { producer, consumer });

public void Process<T>(IProducer<T> producer, IConsumable<T> consumer)
{
  producer.Consumer = consumer;
}

您要為MyType提供> 1 IConsumable並只是更改泛型類型參數嗎? 我想你是因為你得到了這些接口的清單。 我不知道您從何處獲得制作人,但不使用反射的唯一方法是保持反射。 您可以考慮強制每個“ MyType”提供一種“設置”生產者列表的方法(MyType內部會知道所有它們自己的消耗品類型)。 根據將生產者從何處拉出(內部到MyType或外部),可能必須執行以下操作:

public interface IProducer { }

public interface IProducer<T> : IProducer
{
  IConsumable<T> Consumer { get; set; }
  void Produce();
}

public interface IConsumableProvider
{
  void SetupProducers(params IProducer[] producers);
}

public class MyType : 
  IConsumable<int>,
  IConsumable<double>,
  IConsumableProvider
{
  public void Consume(int item)
  {
    throw new NotImplementedException();
  }

  public void Consume(double item)
  {
    throw new NotImplementedException();
  }

  public void SetupProducers(params IProducer[] producers)
  {
    (producers[0] as IProducer<int>).Consumer = (this as IConsumable<int>);
    (producers[1] as IProducer<double>).Consumer = (this as IConsumable<double>);
  }
}

我不喜歡該解決方案,但我認為最佳解決方案將需要有關您當前代碼庫的更多信息-否則,我給出的答案將與您已經擁有的解決方案過於不同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM