Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 定义实现泛型的接口依赖项_C#_.net_Generics - Fatal编程技术网

C# 定义实现泛型的接口依赖项

C# 定义实现泛型的接口依赖项,c#,.net,generics,C#,.net,Generics,这将是泛型101为许多,但下面是示例代码,所以我可以更好地理解 public interface IRecordedItemsProcessor<T> { ObservableCollection<RecordedItem> Load(string name); void Save(); RecordedItem Parse(T itemToParse); } public class FileLoadingProcessor : IRecord

这将是泛型101为许多,但下面是示例代码,所以我可以更好地理解

public interface IRecordedItemsProcessor<T>
{
    ObservableCollection<RecordedItem> Load(string name);
    void Save();
    RecordedItem Parse(T itemToParse);
}

public class FileLoadingProcessor : IRecordedItemsProcessor<string>
{
    public ObservableCollection<RecordedItem> Load(string name)
    {
    }

    public void Save()
    {
    }

    public RecordedItem Parse(string itemToParse)
    {
    }
}

public class MyClass
{
    public MyClass(IRecordedItemsProcessor<T> processor)
    {

    }

}
公共接口IRecordedItemsProcessor
{
ObservableCollection负载(字符串名称);
作废保存();
recordeditemparse(T itemToParse);
}
公共类文件加载处理器:IRecordedItemsProcessor
{
公共ObservableCollection加载(字符串名称)
{
}
公共作废保存()
{
}
public RecordedItem Parse(string itemToParse)
{
}
}
公共类MyClass
{
公共MyClass(IRecordedItemsProcessor处理器)
{
}
}
问题是,
MyClass
需要依赖于
IRecordedItemsProcessor
,但不会编译,因为它不知道
T
是什么。如何解决这个问题?让MyClass实现a似乎有些奇怪,因为它所需要做的只是调用Load/Save


谢谢

第一个解决方案是最简单的:将泛型声明提升到类级别,如

public class MyClass<T>
{
    public MyClass(IRecordedItemsProcessor<T> processor)
    {

    }
}
第二种解决方案是从构造函数中删除泛型输入并推断类型。然后,您不需要精确地从调用中指定泛型。类声明如下所示:

public class MyClass
{
    public void Process<T>(IRecordedItemsProcessor<T> processor)
    {

    }
}
其思想是,您总是需要显式地指定类级泛型,但方法级泛型可以由编译器推断出来

第三种解决方案是将创建机制封装在
MyClassFactory
中。这是非常灵活的,但它可能看起来有点复杂,因为
IRecordeditMSProcessor
的后代不在类级别定义泛型,所以我们应该转到实现的接口并获取泛型类型。只有这样,我们才能构造泛型
MyClass
。清单如下:

public class MyClassFactory
{
    public MyClass<T> MakeMyClassFor<T>(IRecordedItemsProcessor<T> processor)
    {
        var processorGenericType = processor.GetType()
                                            .GetInterfaces()
                                            .Single(intr=>intr.Name == "IRecordedItemsProcessor`1")
                                            .GetGenericArguments()[0];
        var myClassType = typeof(MyClass<>).MakeGenericType(processorGenericType);
        return Activator.CreateInstance(myClassType, processor) as MyClass<T>;
    }
}

这三种方法各有利弊。考虑一下你将要使用的上下文。 第一个解决方案是最简单的:将泛型声明提升到类级别,如

public class MyClass<T>
{
    public MyClass(IRecordedItemsProcessor<T> processor)
    {

    }
}
第二种解决方案是从构造函数中删除泛型输入并推断类型。然后,您不需要精确地从调用中指定泛型。类声明如下所示:

public class MyClass
{
    public void Process<T>(IRecordedItemsProcessor<T> processor)
    {

    }
}
其思想是,您总是需要显式地指定类级泛型,但方法级泛型可以由编译器推断出来

第三种解决方案是将创建机制封装在
MyClassFactory
中。这是非常灵活的,但它可能看起来有点复杂,因为
IRecordeditMSProcessor
的后代不在类级别定义泛型,所以我们应该转到实现的接口并获取泛型类型。只有这样,我们才能构造泛型
MyClass
。清单如下:

public class MyClassFactory
{
    public MyClass<T> MakeMyClassFor<T>(IRecordedItemsProcessor<T> processor)
    {
        var processorGenericType = processor.GetType()
                                            .GetInterfaces()
                                            .Single(intr=>intr.Name == "IRecordedItemsProcessor`1")
                                            .GetGenericArguments()[0];
        var myClassType = typeof(MyClass<>).MakeGenericType(processorGenericType);
        return Activator.CreateInstance(myClassType, processor) as MyClass<T>;
    }
}

这三种方法各有利弊。考虑一下你将要使用的上下文。 您可以执行以下操作:

var myClass = new MyClass<string>(new FileLoadingProcessor());
Console.WriteLine (myClass);
  • 创建一个新接口
    IRecordedItemsProcessor
    (非通用)
  • Load
    Save
    移动到此
    IRecordedItemsProcessor
  • 使
    IRecordedItemsProcessor
    从此
    IRecordedItemsProcessor
  • 使
    MyClass
    expect
    IRecordedItemsProcessor
    在其构造函数中

  • 这清楚地表明,
    MyClass
    不关心处理器可以解析什么类型的东西,甚至根本不关心它可以解析什么东西——它只知道它可以保存和加载。

    您可以执行以下操作:

    var myClass = new MyClass<string>(new FileLoadingProcessor());
    Console.WriteLine (myClass);
    
  • 创建一个新接口
    IRecordedItemsProcessor
    (非通用)
  • Load
    Save
    移动到此
    IRecordedItemsProcessor
  • 使
    IRecordedItemsProcessor
    从此
    IRecordedItemsProcessor
  • 使
    MyClass
    expect
    IRecordedItemsProcessor
    在其构造函数中

  • 这清楚地表明,
    MyClass
    不关心处理器可以解析什么类型,甚至根本不关心它可以解析东西——它只知道它可以保存和加载。

    泛型类型,如所写,正在
    MyClass
    构造函数上声明,这意味着必须在
    MyClass
    级别定义泛型类型:

    public class MyClass<T>
    {
        public MyClass(IRecordedItemsProcessor<T> processor)
        {
    
        }
    }
    
    公共类MyClass
    {
    公共MyClass(IRecordedItemsProcessor处理器)
    {
    }
    }
    
    但是,如果泛型类型是在方法级别声明的,则只需在方法级别定义它:

    public class MyClass
    {
        public void MyMethod<T>( IRecordedItemsProcessor<T> processor )
        {
    
        }
    }
    
    公共类MyClass
    {
    public void MyMethod(IRecordedItemsProcessor处理器)
    {
    }
    }
    
    编辑
    根据您的评论:

    我想要一个可以调用Load/Save方法但不必担心的类 那不是

    然后需要两个接口:一个用于加载/保存,另一个用于解析。在这种情况下,您可以使用继承:

    public interface IRecordedItems
    {
        ObservableCollection<RecordedItem> Load( string name );
        void Save();
    }
    
    
    public interface IRecordedItemsProcessor<T> : IRecordedItems
    {
        RecordedItem Parse( T itemToParse );
    }
    
    public class MyClass : IRecordedItems
    {
        #region Implementation of IRecordedItems
    
        public ObservableCollection<RecordedItem> Load( string name )
        {
            throw new NotImplementedException();
        }
    
        public void Save()
        {
            throw new NotImplementedException();
        }
    
        #endregion
    }
    
    公共接口IRecordedItems
    {
    ObservableCollection负载(字符串名称);
    作废保存();
    }
    公共接口IRecordedItems处理器:IRecordedItems
    {
    recordeditemparse(T itemToParse);
    }
    公共类MyClass:IRecordedItems
    {
    #IRecordedItems的区域实现
    公共ObservableCollection加载(字符串名称)
    {
    抛出新的NotImplementedException();
    }
    公共作废保存()
    {
    抛出新的NotImplementedException();
    }
    #端区
    }
    
    编辑2
    根据您的选择,可以将类型依赖项从接口中移出,直接移到接口方法中:

    public class RecordedItem {}
    
    public interface IRecordedItemsProcessor
    {
        ObservableCollection<RecordedItem> Load( string name );
    
        void Save();
    
        RecordedItem Parse<T>( T itemToParse );
    }
    
    public class MyClass
    {
        private readonly IRecordedItemsProcessor _processor;
    
        public MyClass( IRecordedItemsProcessor processor )
        {
            _processor = processor;
    
            processor.Parse<string>( "foo" );
            processor.Parse<int>( 10 );
            processor.Parse<RecordedItem>( new RecordedItem() );
        }
    }
    
    公共类RecordedItem{}
    公共接口IRecordedItemsProcessor
    {
    ObservableCollection负载(字符串名称);
    作废保存();
    recordeditemparse(T itemToParse);
    }
    公共类MyClass
    {
    专用只读IRecordedItemsProcessor\u处理器;
    公共MyClass(IRecordedItemsProcessor处理器)
    {
    _处理机=