Is it possible to make an object expose the interface of an type parameter?

后端 未结 2 1420
盖世英雄少女心
盖世英雄少女心 2021-01-05 06:40

In C#, is it possible to write something like this:

public class MyClass : T 
    where T : class, new() 
{
}

I know that the abov

相关标签:
2条回答
  • 2021-01-05 06:56

    This isn't possible.

    In my opinion, I don't think that a wrapper should be implemented using inheritance.

    For example, let's say we've an Engine class and you need to implement a FerrariEngine. And you have a Car class.

    You're saying that Car should inherit FerrariEngine. It looks terrible for me!

    At the end of the day, you're looking to do something like dependency injection using inheritance and, again, this isn't the right path.

    My suggestion is don't try to make your life easier: decide an architecture based on rational points.

    UPDATE

    The OP said in some comment:

    I want to make this class to manage instances of objects of type T, so that the client does not need to take care of when the instances need to be created.

    You don't need to make strange things to get what you want:

    public interface IEngine 
    {
         void Start();
    }
    
    public sealed class FerrariEngine : IEngine
    {
         public FerrariEngine()
         {
              Start();
         }
    
         public void Start()
         {
         }
    }
    
    public abstract class Car<TEngine> where TEngine: IEngine, new()
    {
        public Car()
        {
            _engine = new Lazy<TEngine>(() => new TEngine());
        }
    
        private readonly Lazy<TEngine> _engine;
    
        public TEngine Engine
        {
            get { return _engine.Value; }
        }
    }
    
    public class FerrariCar : Car<FerrariEngine>
    {
    }
    

    Finally, if we create an instance of FerrariCar:

    Car<FerrariEngine> myFerrari = new FerrariCar();
    

    The engine will be instantiated and started, without developer intervention!

    Check how Lazy<T> and basic generic constraints make the job ;)

    In summary:

    • Using Lazy<T> the engine will be instantiated only when some access the Engine property.
    • Once the lazy-loaded engine is instantiated, since FerrariEngine implements a parameterless constructor calling Start() itself, it will start the engine.

    I believe that this sample illustrates you how you can get what you're looking for and using C# "as is"!

    0 讨论(0)
  • 2021-01-05 07:12

    You could have a look at DynamicObject and do something like this:

    class Foo<T> : DynamicObject
    {
        private T _instance;
        public Foo(T instance)
        {
            _instance = instance;
        }
        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            var member = typeof(T).GetProperty(binder.Name);
            if (_instance != null &&
                member.CanWrite &&
                value.GetType() == member.PropertyType)
            {
                member.SetValue(_instance, value, null);
                return true;
            }
            return false;
        }
    
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            var member = typeof(T).GetProperty(binder.Name);
            if (_instance != null &&
                member.CanRead)
            {
                result = member.GetValue(_instance, null);
                return true;
            }
            result = null;
            return false;
        }
    }
    
    class Bar
    {
        public int SomeProperty { get; set; }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            var bar = new Bar();
            dynamic thing = new Foo<Bar>(bar);
            thing.SomeProperty = 42;
            Console.WriteLine(thing.SomeProperty);
            Console.ReadLine();
        }
    }
    
    0 讨论(0)
提交回复
热议问题